
Metaclasses: Thoughts on generative C++ - panic
https://herbsutter.com/2017/07/26/metaclasses-thoughts-on-generative-c/
======
Negitivefrags
You could make one hell of a good C++ web framework with this.

    
    
      http::controller mypage
      {
        //Browsing to http://server/mypage/test?some_str=blah&param=5 calls this
        http::response test( const std::string& some_str, const unsigned param )
        {
          return web::response{ 200, "You did awesome stuff" };
        }
    
        //This method can only be called with HTTP POST
        [[POST]] http::response save_some_data( const std::string& blah ) 
        {
          return 200;
        }
      };
    
      int main()
      {
        http::server server( "localhost", 80 );
        server.add_route( "mypage", std::make_unique< mypage >() );
        server.run();
      }
    

It's all the magic of a modern web framework but in a fast language.

Due to web assembly you can easily have your server and client side scripting
be done in the same language, with the same libraries which is also huge
bonus.

I honestly can't think of a better stack.

~~~
EGreg
Sorry but can someone explain why C++ by itself can't be good enough for a web
framework? OKCupid wrote one back in the day.

ALSO: Your example is much slower than the same server written in Node.js,
haha. Because the language doesn't support evented programming. The language
may be fast, but the paradigm of blocking while waiting for I/O is slow!

~~~
pjc50
Ahem.

Back in 2001 I was working on what was at the time the fastest webserver in
the world: Zeus. It was written in C++ and built around select(), which gave
it effectively evented programming. One process per core. Primarily for
serving static content, although there was a fastcgi interface and, god help
you, IBM Websphere integration.

There were a few quirks to the codebase. No STL; instead our own containers
and length-based string classes. There was also a "stringrange" type class,
which referred to a range of a longer string. So it parsed in the entire HTTP
header as an octet array, then created objects to refer to individual headers.
Since the input header was immutable this worked beautifully. Considerable
effort was put into avoiding unnecessary copies.

It also had at least a dozen target platforms; Linux, SunOS, IRIX, and
architectures from ARM to Itanium. I'm not sure on how many of those we ever
sold a license.

~~~
EGreg
I remember that server! It's really cool stuff, and select() can definitely be
used in C++. But there is no real evented ecosystem for mysql, pgsql,
websockets, and all the other types of I/O unless it is all done through
sockets. I think all languages can do an event loop, it's just a question of
the ecosystem. Javascript is designed around async and Node.js was heavily
promoting it from the beginning. So the default pattern is async. That's what
I meant.

Yes, sure you can do the web server and even middleware as async, but there
are many services (redis, memcached etc.) and having async modules for them
all is the key.

------
mannykannot
Anything Mr. Sutter says is well worth consideration, and this is no
exception. I would like to raise one concern, however, that applies to all
such proposals for simplifying programming by adding more powerful
abstractions to the language: I hope as much effort is put into debugging, _at
the semantic level of the source code_ , as is put into generating code. In
this regard, this quote from the paper leaves me feeling uneasy:

'Enable writing many new “specialized types” features (e.g., as we did in
C++11 with enum class) as ordinary library code instead of pseudo-English
standardese, with equal usability and efficiency, _so that they can be unit-
tested and debugged using normal tools_ ' (my emphasis.)

Sometimes, of course, you have to go below that level to figure out what is
wrong, but is better if you do not have to do so unless it is unavoidable in
principle.

------
lultimouomo
A snippet from the paper that made me understand what this is about:

    
    
      // $ is the reflection operator and T is a type.
      constexpr { // execute this at compile time
       for... (auto m : $T.variables()) // examine each member variable m in T
         if (m.name() == “xyzzy”) // if there is one with name “xyzzy”
           -> { int plugh; } // then inject also an int named “plugh”
      }
    

This would inject "int plugh;" in the scope surrounding the constexpr block.

~~~
ta834939874
reminds me of [http://terralang.org/](http://terralang.org/)

~~~
tomovo
also Jai:
[https://www.youtube.com/watch?v=gWv_vUgbmug](https://www.youtube.com/watch?v=gWv_vUgbmug)

~~~
_pmf_
I have hopes that Jai will be at a very nice local optimum regarding
performance and productivity, but I think just like in C++, safety is not a
major design goal (you need to be unsafe if working with memory mapped
structs).

~~~
Rusky
> you need to be unsafe if working with memory mapped structs

Perhaps when defining their address and layout, or if they are a hardware
structure that affects memory like a page table or TLB or a DMA controller,
but beyond that, why? Or is that just the main use case you're describing?

------
tmpmov
Just as others have noted, I'm worried about the intermediate representation
hiding necessary details. Here's an example:

If I'm looking at one of these classes that have been compile time injected
with new functionality, is there an easy way to see what's been added without
looking at these compile time injections? Specifically, it would be great if
there was support for looking at both the source code before the injections
and the source code after the injections in an easy way (built in IDE support
for example).

While different from what's being proposed here, C/C++ macros can be used for
massive amounts of code generation, but looking behind the curtain of the
macros involves running your source code through the preprocessor. Getting to
the intermediate representation for macros feels tedious and most IDEs have
limited support to aide the programmer pulling the veil off of macro code
generation. I can imagine (*though maybe wrong) that a similar problem exists
for certain types of template meta programming.

~~~
tmpmov
Note that I think this is still a great idea. In fact, I'm rooting for it to
come to C++! However, I think IDE plugins will need to catch up (shouldn't be
too bad if metaclasses are adopted and once clang et al add support).

Very neat stuff.

------
Animats
Are they trying to catch up to Rust while maintaining backwards compatibility?
Or what?

C++ needs the full definition of a class, including its private members,
before you can use its methods. This is a huge dependency headache. Most later
languages have interfaces or traits or something to decouple class definition
and interface definition. This looks like an attempt to deal with that. Of
course, this is a retrofit, so it's going to be messy.

C++ has a lot of baggage. It may have exceeded its excess baggage allowance.
The basic problem with C++ is that it has heavy encapsulation without memory
safety. No other language has that. Either nothing is hidden, as with C, or
the language is memory-safe, as is almost everything since C++.

~~~
eej71
Rather than specifically single it out as "trying to catch up to Rust", I'd
say that C++ is doing what it has always been doing. Reaching for the future
while maintaining backwards compatibility. It's been a great strategy for 30
years and I hope they keep at it.

~~~
nemaar
>It's been a great strategy for 30 years and I hope they keep at it.

I wouldn't say that it's been _great_. The evolution of C++ is insanely slow.

~~~
dom0
> The evolution of C++ is insanely slow.

The only language today with more independent implementations than C++ is C.
Compared to C, C++ evolution is not slow — processes involving so many
implementers are inherently not in fast-forward mode.

Most major languages only have a handful of active implementations, if it's
not just one implementation. Most don't have specs.

~~~
ThatGeoGuy
I would argue that you're eschewing Lisp and Scheme in terms of independent,
active implementations, however in a more general sense I agree.

Moving fast (and breaking things) is just not what the standardization
committee does, and that's fine. They can move faster since C++11/14, but
sometimes you really don't want a giant moving target with new features all
the time. I think their approach works for the kind of environment you find
C++ used in.

------
pzone
Wow, not sure what to think of this. Seems like this merely grows the monster
that is the C++ specification, yet at the same time I wouldn't mind wiping out
all that boilerplate.

~~~
pjmlp
Can you fit the Python 2.x and 3.x differences all on your head, including
differences between each single release and all the included batteries?

~~~
makapuf
I'm not sure you can compare the complexity of using the majority of Python3
to modern C++. Besides, the switch to python 3 happened once in ten years. The
complexity of the change is I think lower than the introduction of c++11 or
14. BTW I like C++ but its complexity is daunting. What subpart is relatively
simple to use ? How would you start now ?

------
eigenbom
I'm excited by this feature, along with all the other compile-time programming
stuff (reflection, concepts). The downside I see is having to remember how a
metatype works.. e.g., the default access type for member variables of struct,
class, interface, value, .. and on and on. But if we keep the number of
metatypes low, this may manageable.

------
dmytrish
The thing that makes me uneasy about the proposed implementation of
metaclasses is that imperative code is used for code generation instead of
declarative specifications.

Simple examples are relatively simple and predictable, but anything more
complex might blow up into incomprehensible mess pretty quickly.

------
iainmerrick
Metaclasses for things like "interface" and "value" sound fantastic, and will
get rid of huge amounts of boilerplate, but I wonder how flexible they really
are.

I don't immediately see a way to implement something like C#'s extension
methods, or Objective-C categories, for example -- extending classes with new
methods. Those are incredibly useful when integrating with an existing
codebase.

Metaclasses just seem like a way to do existing C++ stuff in a cleaner and
terser way. Definitely very useful but maybe not a huge game changer.

I'm also concerned at the potential impact on compile times once people start
using metaclasses very heavily; but maybe it won't be as bad as templates in
that respect.

------
Sharlin
With the function-style syntax and general compile-time programming support
this is getting awfully close to full hygienic macro capacity, even if
restricted to outputting type declarations at first.

------
manyoso
He's basically suggesting writing plugins for the compiler.

------
Too
Did I miss something or is this restricted to "inheritance" instead of
composition?

As example I can't make a constraint/metaclass that is both plain_struct,
ordered and final at the same time, maybe that particular example doesn't make
sense practically but I'm sure there are others that do.

------
nialv7
Glad to see C++ become more and more D

------
skolos
I like the flexibility that this feature adds. However I find that C++ is hard
to use without good IDE support and it looks like this feature will not be
properly supported in IDE's for very long time.

~~~
maccard
This feature isn't even supported in compilers yet.

