My CppCon 2017 session is now on YouTube

My CppCon talk yesterday is now on YouTube. You can read more about in my July blog post on “Metaclasses: Thoughts on generative C++” which contains links to the current paper and some examples that work so far on the live prototype compiler cppx.godbolt.org.

Thanks again to Bjarne Stroustrup for making C++ so general and powerful with just a single kind of “class” (essential for this work), to Andrew Sutton for implementing the prototype metaclasses compiler, to Matt Godbolt for hosting it on his site, to everyone on the committee and in the community on whose work this is trying to build and have provided comments and feedback, and to Bash Films and CppCon for making these videos available so quickly. As in previous years, the CppCon videos will also be available on Channel 9 as well, though that usually takes a few extra weeks to happen.

29 thoughts on “My CppCon 2017 session is now on YouTube

  1. Wanted to add my voice on one point, having watched the [excellent] talk:

    I’d really like to see, as a syntax note, the meta class specifier be added as an addendum to “class”, rather than as an alternative name. So for example:

    value class Point { ... };

    Rationale:
    – Lowers to cognitive burden for readers who are not as familiar (ie: if I know what a “class” is, I can sorta read over a “value” prefix, whereas if that’s the magic keyword, I have to know what that is/means)
    – It makes composition easier, outside of creating other new metaclass types, and more explicit in intent
    – (similar to above) It makes composition more potentially iterative, in both directions

  2. @paultopping:

    > Since solving the “CRTP problem” is given as a major motivation for a metaclass mechanism, I just wanted to point out that there may be a simpler solution. And, of course, all things being equal, simpler is better. Perhaps all that is needed are more non-CRTP examples demonstrating how metaclasses will be a good thing.

    I think there needs to be a distinction between “things that the CRTP could do too” and “how metaclasses subsumes CRTP”.

    The CRTP is, at its core, an attempt to get mixins into the language. But like Boost.Lambda, the CRTP comes with a bunch of limitations. The CRTP base class _cannot_ access the class it is mapped into generally; it can only do so in very specific circumstances.

    The simple solution to the CRTP problem is to do what we did with lambdas: add direct support for mixins into the language. And once you get past the reflection introspection and code generation, that is *all* metaclasses are.

    That is, reflective introspection and code generation are ultimately orthogonal to metaclasses as functionality. You can have one without the other. While they make metaclasses *really* powerful, C++ right now could still benefit from metaclasses without them, as they give us language support for mixins.

    Or to put it another way, my equation would better be stated as: reflective introspection + code injection + mixins = the full metaclasses proposal. Herb’s proposal talks about all of them, but the reflection and code injection stuff is proceeding orthogonality to it (as I understand it). The ability to define metaclasses and how they interact with the class that uses them is pure mixin. So there’s no reason we *have* to wait for reflection/code injection before we get mixins.

  3. Composability summary: currently either “serializable interface class” or “class” (or “struct”, I assume). I’m … actually ok with either of those. A slight lean to the former. As you say, similarity to ref class and enum class.

  4. Meta (pun intended): I’m sorely behind on answering blog comments related to P0707, esp. on the July blog post. This is part of a first pass to catch up…

    @Alexey: I have not tried open multi-methods. Re external data, the metaclasses proposal builds on the compile-time programming proposal, so the question is really whether that allows file I/O (which has been suggested).

    @Matthew, several others: Yes, they are composable. See section 6 in the current paper for possible directions on applying multiple metaclasses at once without creating a named metaclass for that combination.

    @Nenad: No, I did not consider a meta-union… because I believe metaclasses are powerful enough to express that so that a special case for union is unnecessary. See the safe_union metaclass in the paper for an example.

    Re CRTP: I was trying to summarize that there are a lot of drawbacks to CTRP, and that one thing we discovered is that metaclasses appear to cover the use cases of CRTP as well, which helps to expose what CRTP was trying to approximate. However…

    @paultopping: … no, “solving the CRTP problem” is not a major motivation, it’s something “that it happens to do too” that was discovered along the way. CRTP is not yet even mentioned in the paper — adding that is on my to-do list.

  5. So!
    Instead of providing programmers with more power, flexibility etc…

    Why do we need the destructor. It would be logical to use it if we don’t need the object any more. Who get tha idej that programmer don’t understand when we need it removed from our memory…

  6. I didn’t have any problems with Herb’s proposal per se. However, your comment causes me to sharpen my point. Since solving the “CRTP problem” is given as a major motivation for a metaclass mechanism, I just wanted to point out that there may be a simpler solution. And, of course, all things being equal, simpler is better. Perhaps all that is needed are more non-CRTP examples demonstrating how metaclasses will be a good thing. Perhaps these exist already. I will admit to not having read everything.

  7. > While metaclasses would obviously be a powerful mechanism, perhaps CRTP could be replaced by something simpler.

    I see no need for that.

    From Herb’s proposal, the basic structure of metaclasses doesn’t actually *require* any of the reflection stuff. That is, reading members and so forth. Any non-injection declarations a metaclass makes go *directly* into the class that uses the metaclass. In that way, it works exactly like the CRTP, only without all of the stupid bits.

    Basically, pure metaclases are C++ mixins. Metaclasses + reflection + injection are what Herb’s talking about.

    The only real downside is that Herb’s current syntax for using a metaclass only lets you use a single metaclass. So if you need to apply multiple metaclasses, you have to make a new metaclass that inherits from them. But that could easily be fixed as follows:

    class(metaclass1, metaclass2) Typename {...};
    

    Which will behave as if you had done:

    $class some_unnamed_metaclass_name : metaclass1, metaclass2 {};
    some_unnamed_metaclass_name Typename {...};
    
  8. I agree. While metaclasses would obviously be a powerful mechanism, perhaps CRTP could be replaced by something simpler. Whenever I’ve used CRTP, the difficulty is in dealing with two classes instead of one. Of course, it is only one at a time. What is desired is multiple classes derived from a single base where the definitions within both are merged into a single class. Or, saying it another way, a different kind of derivation from the base is needed where the base’s definitions are merged into the derived class. Perhaps not as elegant as metaclasses and I am only hand-waving here.

  9. I think I can answer that last question better than Herb did. Herb was trying to get at this point, but I don’t think it came out in full.

    The single biggest annoyance with the CRTP (for me and my uses) is the fact that the derived class does not exist during the instantiation of the CRTP class. While the bodies of member functions of the CRTP class can access members of the derived class, anything else cannot.

    Think about some of the boilerplate that C++ containers require in terms of typedefs. You have value_type, reference, pointer, etc. But really, the only one that the implementer needs to define is value_type; unless they’re doing something special, using reference = value_type&; and using pointer = value_type*; work. So that’s an obvious thing to put into a CRTP base class.

    But that doesn’t work. Or at least, not directly. You cannot write using pointer = Derived::value_type*;, because Derived is an incomplete type at that point in C++’s template instantiation model. So what you have to do is have some traits class which you specialize for your container type, and that class has value_type. So the CRTP does using pointer = typename trait::value_type*;.

    Which means that when I go to write the container that uses this CRTP base class, I have to go through a lot of pain. I have to close my namespace, open up the namespace where the traits class specialization needs to go, specialize it, close that namespace and reopen my namespace, and then finally declare my class. And that’s for a very simple case.

    So while CRTP + reflection + injection can probably get some of the low-hanging metaclasses fruit, it will never be as good as full-frontal metaclasses.

  10. When you got to the portion of the talk about injecting code from the constexpr block into the regular code, I immediately thought that it would make sense to say that this was an `export` operation. Seems like that could be a good keyword for it, and you could save `->` for something else.

  11. Great idea and great feature! I was really hoping to see that in C++20, but I guess we’ll have to wait until at least c++2023 and then until 2025 for MSVC to properly implement it.

    However, what are your thoughts about unions? Did you consider adding

    $union

    keyword for supporting meta-unions, or do you see unions as a special type of metaclass (just like class and struct), but with specific storage rules?

    Too bad no one asked that question in the video.

  12. I like the idea of metaclasses. The proposal contains examples with Qt’s moc substitution.

    Lately you presented us with defer_ptr type.
    I would love to see whether implementation of GarbageCollected type is possible through metaclasses.
    I find this a challenging task. Please consider subclassing, visiting members, etc. in potential solution.

  13. Ironically, I’d suggest creating a preprocessor program to generate the classes etc (cfront++ :) ) from metadata descriptions so as to gain experience with the meta language and make its use with different compilers easier.

    It would also allow much earlier adoption rather than waiting for C++ 2023

  14. Herb, thank you for taking the time to write the metaclasses proposal. I think it is an excellent proposal.. I have thought about the addition of ‘interface’ and ‘abstract’ contextual keywords similarly to how we use the final keyword now. For example:

    class Foo interface
    class Foo abstract
    class Foo final

    . Your proposal is superior as it is extensible. We save having to write ‘class’ each time too! If it won’t be ready in time for C++20 I hope it makes it to a TS so we can start using metaclasses sooner rather than later.

  15. Okay…
    Let’s see. Well, the class is bit different than that template and I will need to have history to make it more clear what is the ground we are now.

    In the start we had some jumbo computers and no body cares about that… then we had some stuff like Commodore, Spectrum and Atari …
    and now we have std with algorithms and we have templates… does that matter too?

    I don’t know. But, where is multi threading as it should be, not as it is?

    Why we don’t build more on that concept of objects and make it more like relationships of the objects that will represent real life even more.
    The templates don’t care about type of the variable and …

  16. I like the general idea of meta classes: writing code that transforms/verifies other code according to some criteria.

    However, I feel there are some problems with the approach, too: It has all the same problems “normal” inheritance already has, plus in some cases it might be too constraining.

    As mentioned beforehand, composability of metaclasses, as far as i understand, is restricted to creating a new metaclass inheriting from all metaclasses whose behavior is desired and using that to declare the final type. Not only does this somewhat reproduce the dreaded inheritance-diamond-problem, it also clutters the code base with possibly single-use metaclasses.

    Of course, this could be handled by introducing utility metaclasses, maybe like this:

    template<$class... T>
    $class class_combinator : T... {};

    But somehow, this doesn’t feel as elegant or concise.

    In normal OOP, the guideline is usually “favor composition over inheritance”. This usually makes sense, especially if the referred classes address orthogonal concepts, as many of the metaclass examples in your presentation do.
    Sadly, I can’t seem to think of a way of expressing this relation in the proposed metaclass implementation.

    One possible solution I can think of would be leveraging some of the metaclasses into class attributes/annotations (whatever you prefer). For example, let’s say I want a Qt widget that is counted and ordered (using the examples from your slides). The proposed implementation for that would be something like this:

    $class MyWidgetClass : QClass, ordered, counted {};
    
    MyWidgetClass MyWidget { /* implementation */ };

    My thoughts would tend to look more like this (using the Java annotation style):

    @ordered
    @counted
    QClass MyWidget {
      /* implementation */
    };
    

    This way, the different concerns are still separated, but clearer. Another possible benefit could be that the transformations done by ordered and counted might be done before the QClass metaclass does its transformations and verifications.

    This way also prevents an explosion of different metaclasses for all conceivable combinations of the metaclasses for these concerns.

    Actually, QClass could possibly also be rewritten into an attribute/annotation, but since it really does change the fundamental semantics (as compared to ordered or counted, which only add some useful functionality), I feel like this would be an appropriate use of a metaclass.

    What do you think about these problems, and what are the problems with my off-the-head solutions (as I figure you’ve probably already thought about these)?

  17. How do you apply multiple metaclasses to the same class? (e.g. you showed value_type, pod_type, EqualityComparable, can I compose them?). Or the more general theme, how do you compose metaclasses?

  18. I’m curious about how composable metaclasses are/should be.

    For example, if I have metaclass “value”, which generates getters and setters a la the talk, and another metaclass called “reflected” which detects getters and setters (etc.) and generates a function to return some type that allows runtime introspection and activation of those functions.

    Under the current proposal, I would need to create a third metaclass, say “reflected_value”, which inherits both of those metaclasses. Could there be a simpler syntax to have this mix-in capability?

  19. Awesome talk, thank you! Generative programming was always a highly desired paradigm to support in C++.

    Two questions:
    1) Is it possible to support open multi-methods as a use case? https://github.com/jll63/openmethods.d
    2) In Generative Programming you can load some external model as an xml/json data (created in tools by non-programmers) and generate some code. Is it out-of-scope for the proposed approach? (So we won’t be able to use any external data in constexpr {} blocks)

  20. While we don’t want to turn C++ into another language, these metaclasses are intended to replace at least some solutions involving “little languages” that are converted to C++ code by external tools. I would like to see support for such “little languages” addressed directly if only to see what additional facilities would have to be added to C++. It seems the metaclass feature, and especially the tooling that comes with it, gets us part way there. Let’s investigate what it would take to go all the way (whatever that means) and see how it might impact what is being proposed here. At a minimum, it would avoid painting ourselves into a corner and make it easier to revisit the decision to support (or not) little languages in the future.

  21. I am big fan of C++, and it was it for me.
    I have learned some other stuff, but C/C++ is the most expressive programming language out there. Yeah, I am not comparative scientist, do I have compared it with other ones.
    The issue I see with C++, is that:
    * multi threading is not done in good way,
    * support for AI is, well there is no support unless you add something to your C++,
    * creating functions dinamically,
    * having good approach to limiting data types and test of it,

    Yeah, there is a lot of the stuff over there that could be fixed, and true evolution need the genuine interest from the people that are involved. Somehow, I don’t see that to the extent that would make me happy…

    So, where does C++ go from here…

    And one big issue for C++ is lack of GUI standard for: Linux, MS, … like something for simple apps…

  22. I believe that in your example both errors could be given with what’s proposed.

    Remember that it’s opt-in. You can tell the compiler to generate a class, then use that class/struct your code instead, and it should be able to be used. Ideally, you would copy the metaclass and remove the constrants that you don’t want. Also, metaclasses are not only for constraits; properites for Qt, CLR (WPF, Noesis GUI etc.), or other change notification systems could be added with metaclasses, which dramatically removes boilerplate code.

  23. JMS, does it really matter which one is tested first? I would think it’s actually a good thing that this is not ambiguous, so that we get consistent results from all the compilers/libraries.

  24. You gave your usual excellent talk.

    Code that specifies rules is often both terser and easier to write correctly than is an English equivalent. However, couldn’t a code specification introduce needless constraints? For example, say that metaclass “M” bans both private functions and virtual functions. If a careless author writes a private virtual function in an “M” class, which rule is tested first, the one banning “private” functions or the one banning “virtual” functions? A specification in English can leave this detail up to the implementation but a specification in code cannot; it must commit to one order or the other. This may be a trivial example but I wonder if more consequential examples of over-specification are possible or even unavoidable. I don’t know enough about metaclasses to know whether this is a risk.

    Thank you.

  25. I’ve been waiting for more talks on this subject. I’d really like this in MSVC, main-line Clang, and Gcc!

Comments are closed.