1. 9

  2. 4

    It hurts me to see how much C++ neglects the problem of compile time reflection, even though it’s absolutely crucial in:

    • Entity component systems (ECS), e.g. for video games and 3D engines
    • Marshalling/unmarshalling of data packets
    • Serialization/deserialization of JSON, XML, etc.
    • Storing and loading objects to and from databases
    • Printing or dumping object contents, e.g. for debugging purposes

    And every nontrivial application will grow to do at least one of these things. It’s just such a pain… I ended up writing a set of C++98 (I need to support ancient compilers) compliant macros that are minimally obscure and give me a powerful reflection API. You have to wrap the class/struct member declarations into a macro but it’s rather painless. Since then I haven’t used anything else. But since I’ve learned Rust, the ugly kludges that are required all day every day to implement ordinary C++ applications give me headaches and I started pivoting away from C++ wherever possible.

    1. 3

      C++ hasn’t neglected compile-time reflection, it’s just really hard to get right and once you’ve defined the interfaces for it then you’re stuck with them basically forever. It’s likely to be part of C++23, the reflection TS has been gradually approaching convergence for the last few years.

      1. 1

        The first C++ standard was released in 1998. We now speculate that compile time reflection will be part of the standard in 2023. That’s a quarter century later than it should have been made part of the language. During this time, the C++ committee introduced a myriad of less useful language features. Yes, that is neglect. Do you know how long it will take for this feature to be supported on embedded devices whose compilers notoriously lag behind? Maybe in 2030 or 2040 I will be able to use compile time reflection in a real product.

        1. 1

          Looking forward to it. I love the kind of stuff you can do in Zig — like writing a “for” loop over the fields of a struct. So intuitive!

          Are there any articles that describe the C++ reflection proposals in layman’s terms?

          1. 1

            There is 4 year-old article with title: ‘Reflections on C++ reflection proposals

            I like the title quite a bit :-)

        2. 1

          You have to wrap the class/struct member declarations into a macro

          Yep, I have been doing the same. I am thinking to do ‘an upgrade’ (for my ’09 code) to, now, use const expressions (although, I also like the approach proposed in [1] with CMake).

          I would also add to your list of critical ‘capabilities’ of a modern programming language, where reflection is needed – is the support of declarative and reactive GUI.

          Without reflection feature, every GUI library developer – brings their own reflection feature.

          Mature languages, like C++ need something like –error-on-undefined-behavior-features compile time switch, such that when used the compiler will error out on usage of library calls, idioms, language features that do not have a well defined standard behavior.

          This switch should also affect if a given precompiled ‘module’ can be used or not.

          This way, may be we could the language standard and its implementation to evolve a little faster. And the community usage around new features will grow faster.

          [1] https://onqtam.com/programming/2017-09-02-simple-cpp-reflection-with-cmake/

        3. 3

          Bliss might not be the first word to come to mind when seeing the final implementation but hey it really seems to work. I’d be tempted to replace constexpr auto name() { return "α"; } with a macro param(name, "α") :)

          Also I thought this was really funny:

          The technique is basically a band-aid until we get true reflection: it counts the fields by checking whether the type T is constructible by N arguments of a magic type convertible to anything, and then uses destructuring to generate tuples of the matching count.

          Anyway, very useful stuff. Saving this for future reference.

          1. 1

            hi, op here :)

            Bliss might not be the first word to come to mind when seeing the final implementation

            Something which was maybe not that clear in the article is that the “bliss” part is only for the algorithms authors, not for the person who writes the binding code (which is indeed extremely hairy until actual reflection becomes standard instead of whatever hack people can find within C++).

            From my point of view, how hairy writing the binding code really does not matter, because the ratio of algorithms-to-APIs is so heavily skewed towards the algorithms it’s not even funny.

            For instance, KVR, a database of audio plug-ins, references roughly 18000 plug-ins, most of them based on the VST2 and 3 APIs. So no matter how hard writing the binding code is, it’s still worth to do it because one person writing that binding code will potentially make the life of thousands of developers, who’ll be able to just write simple structs, much better.

            I’d be tempted to replace constexpr auto name() { return “α”; } with a macro param(name, “α”) :)

            yep, basically having a way to state clearly “this is some constant meta-class information” would be neat.

            1. 1

              Hard agree. Maintaining native-to-whatever glue code really sucks and no C++ magic can be uglier than debugging a “happens only on IL2CPP build on iOS” bug because you forgot to add a struct member somewhere. Luckily I wasn’t responsible for tracking down that one :)

              Thanks for sharing this technique.