Live data from Hacker News

Cost of enum-to-string: C++26 reflection vs. the old ways

vittorioromeo.com

81–90 of 189 posts

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#81

Another win for X macros and for C style in general, though the author didn’t declare it as such.

The downside is, of course, that it's ugly and very awkward to use. That's the essence of C++: you're basically trading ergonomics for compile times.

Are X macros awkward? I find them very straightforward and clear.

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#82
post #57

Never quite understood why people are so obsessed with meta programming capabilities in a language, be it templates, comptime, macros, whatever. I program mostly in C, if I need 'meta' programming I just write another C program that processes C source code (I've written a simple C parser), then in my build script I build in two stages, build meta program, run it, build rest of program. Simple, effective, debuggable (…

Actually why even specify metaprogram as C like source code? It must be convenience. But there is little practical use, like a good program always models a lot of different representations of more or less the same things, just recombined and processed a little differently. Why would we want to deal with semantics of C types for example, if we can model a much clearer and better constrained universe of types used in e.g. a de/serialization framework? Even only pointers are quite special, and often only of very immediate use, but there is no point in e.g. persisting them to disk or sending them over the network.

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#83
post #57

Never quite understood why people are so obsessed with meta programming capabilities in a language, be it templates, comptime, macros, whatever. I program mostly in C, if I need 'meta' programming I just write another C program that processes C source code (I've written a simple C parser), then in my build script I build in two stages, build meta program, run it, build rest of program. Simple, effective, debuggable (…

This works for extreme needs. But you're probably not doing s ton of metaprogramming all the time like you should be, and would with a language that allows it. The lack of metaprogramming is also why C is so slow compared to C++

C is not slow compared to C++, that is a strange myth.

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#84
post #57

Never quite understood why people are so obsessed with meta programming capabilities in a language, be it templates, comptime, macros, whatever. I program mostly in C, if I need 'meta' programming I just write another C program that processes C source code (I've written a simple C parser), then in my build script I build in two stages, build meta program, run it, build rest of program. Simple, effective, debuggable (…

This works for extreme needs. But you're probably not doing s ton of metaprogramming all the time like you should be, and would with a language that allows it. The lack of metaprogramming is also why C is so slow compared to C++

C is not slow compared to C++. C++ compilation time are slow though.

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#85
> The header is the cost. Not the reflection. The reflection algorithm is fast – asymptotically ~0.07 ms per enumerator, essentially the same as the hand-rolled switch in the X-macro version (~0.06 ms). What makes reflection look expensive is : just including it costs ~155 ms per TU over the baseline.

So speaking of old ways, I'm not a C++ dev, but a while ago saw someone comment that they still organize their C++ projects using tips from John Lakos' Large-scale C++ software design from 1997, and that their compile times are incredibly fast. So I decided to find a digital copy on the high seas and read it out of historical curiosity. While I didn't finish it, one wild thing stood out to me: he advised for using redundant external include guards around every include, e.g.

     #ifndef INCLUDED_MATH
     #include 
     #define INCLUDED_MATH
     #endif
The reason for this being that (in 1997) every include required that the pre-processor opened the file just to check for an include guard and reading it all the way to the end to find the closing #endif, causing potentially O(N*2) disk read overhead (if anyone feels like verifying this, it's explained on pages 85 to 87).

Again, that was in 1997. I have no idea what mitigations for this problem exist in compilers by now, but I hope at least a few, right?

This conclusion is making me wonder if following that advice still would have a positive impact on compile times today after all though. Surely not, right? Can anyone more knowledgeable about this comment on that?

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#86
post #81

Earlier quoted context omitted.

The downside is, of course, that it's ugly and very awkward to use. That's the essence of C++: you're basically trading ergonomics for compile times.

Are X macros awkward? I find them very straightforward and clear.

The implementation doesn't look too bad, but the usage is terrible:

  #define E_LIST(X) \
      X(V0) X(V1) X(V2) X(V3)

  DEFINE_ENUM(E, E_LIST)
That's not how I want to declare my enums...

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#87
post #2

Oof, that first example (the idiomatic C++26 way) looks so foreign if you're mostly used to C++11.

I was very curious to see what C++ 26 brings to the table, since I haven't used C++ in a while. When I saw the 'no boilerplate' example, the very first thought that came to my mind: This is the ugliest, most cryptic and confusing piece of code I've ever seen. Calling this 'no boilerplate' is an insult to the word 'boilerplate'. Yeah, I can parse it for a minute or two and I mostly get it. But if given the choice, I'd…

As a developer who doesn't really write C++ code I'm inclined to agree, but I think Herb Sutter's "syntax 2" project might provide a nice way out of that mess eventually.

I played around with cppfront over Christmas and it was a lot more ergonomic than my distant memories of C++11, which I don't even have negative memories of per se.

[0] https://github.com/hsutter/cppfront

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#88
post #2

Oof, that first example (the idiomatic C++26 way) looks so foreign if you're mostly used to C++11.

I wish I understood the reason for the `std::define_static_array`... Why can't `std::meta::enumerators_of` just return something that can be iterated through????

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#89
post #4

I've been wondering about debug-ability of code using reflection. X-Macros are quite annoying to step through in most debuggers, though possible. While the code in the first example is evaluated fully at compile-time, how would you approach debugging it?

Why people are still using debuggers? I never felt the need for them when doing TDD.

Because sometimes you have bugs and you haven't narrowed down the cause enough to write a proper test for it?

Re: Cost of enum-to-string: C++26 reflection vs. the old ways

#90

> The header is the cost. Not the reflection. The reflection algorithm is fast – asymptotically ~0.07 ms per enumerator, essentially the same as the hand-rolled switch in the X-macro version (~0.06 ms). What makes reflection look expensive is : just including it costs ~155 ms per TU over the baseline. So speaking of old ways, I'm not a C++ dev, but a while ago saw someone comment that they still organize their C++ pr…

This cost is not significant nowadays, it's the frontend/parsing time.

You can also use `#pragma once` which works everywhere, is nicer, and technically needs less work by the compiler, but compilers have optimized for include guards since a long time ago.

Some random measurements I found: https://github.com/Return-To-The-Roots/s25client/issues/1073

Post reply on HN