Live data from Hacker News

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

vittorioromeo.com

41–50 of 189 posts

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

#41
post #27
post #23

Earlier quoted context omitted.

Serialization is the canonical example. Being able to turn struct MyStruct { int val = 42; string name = "my name"; }; into { "val": 42, // if JSON had integers, and comments of course "name": "my name", } is incredibly powerfuly. If reflection supported attributes (i can't believe it shipped without, honestly), then you could also mark members as [[ignore]] and skip them.

It is powerful, but I'm not sure it is a good idea. Other languages have it, and there is lots of experience in all the ways things go wrong in the real world. I'm inclined to say you should hand write this code because eventually you will discover something weird anyway.

Can you give an example of a language ecosystem that went with reflection-based JSON serialization/deserialization and then went on to regret it? I can't think of any, and don't agree with your conclusion. It works great, and manually writing serialization and matching deserialization code is terrible, annoying, error-prone work.

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

#42
post #11

Earlier quoted context omitted.

C++ conference speakers (including keynotes) are now begging everyone to stop using enum to string in their example. While they are a simple and easy to understand example, reflection is for much more interesting problems. I can't think of any other example that I would type into a comment box or put on a slide.

It comes up pretty frequently in java. Serialization/Deserialization, adding capabilities based on type, Adding new capabilities to a type, general tuning (for example, adding a timing or logging call onto methods). Almost all the Java web frameworks are giant balls of reflection. Name a function the right way or add the right magic annotation and the framework will autowire it correctly. It's a pretty powerful tool.…

Java reflection is another beast altogether as it is runtime reflection. C++26 reflection is purely compile-time, which not only means it adds zero runtime cost, but also prevents those kind-of-insane use cases you see in Java and C#.

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

#43
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…

It is "cryptic" and "ugly" to you just because you're not familiar with it. You'd pick the macro-based implementation because you are familiar with it.

Seeing this argumentation is so tiresome, because it feels like there is a lack of self-awareness regarding what is "familiar" and what isn't, which is subconsciously translated to "ugly" and "bad".

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

#44
post #18

"Enum to string" We've come full circle huh? Why do you need this, logging? In that case I would rather reflect the logging statement to pribt any variable name, or hell, just write out the string. If saving for db, maybe store as string, there's more incentive for an enum in the db, if that's a string you might as well. At any rate it doesn't seem a great idea to depend on a variable name, imagine changing a variabl…

Logging, debugging, auto-generation of UIs/editors, etc... This is an extremely common operation and for a good reason.

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

#45

I don't see how a library like Enchantum could handle everything reflection does. (How) does it figure out duplicate enum values, for example? And (how) does it discover arbitrarily large, discontiguous ranges? And (how) does it do these on MSVC?

In short, it probes enum values in a pre-defined range (e.g. [-256; 256]), and parses the `__PRETTY_FUNCTION__` macro at compile-time to extract the name of the enumerator.

Once you have that in place, you can easily detect duplicates, etc...

Of course, there are major limitations, as it's all a big hack: https://github.com/ZXShady/enchantum/blob/main/docs/limitati...

Similarly interesting is Boost.PFR, which gives you reflection superpowers since C++14: https://github.com/boostorg/pfr

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

#46

Earlier quoted context omitted.

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…

It is "cryptic" and "ugly" to you just because you're not familiar with it. You'd pick the macro-based implementation because you are familiar with it. Seeing this argumentation is so tiresome, because it feels like there is a lack of self-awareness regarding what is "familiar" and what isn't, which is subconsciously translated to "ugly" and "bad".

Have you ever used other (modern) programming languages ?

In a lot of languages, you achieve the same with 1 line of code. It's not about familiarity, it's about the fact that it's a long and convoluted incantation to get the name of an enum.

Why do I have to be familiar with all those weird symbols just to do a trivial thing ?

Update:

Zig:

const Color = enum { red, green, blue };

const name = @tagName(Color.red); // "red"

Rust:

#[derive(Display)]

enum Color { Red, Green, Blue }

let name = Color::Red.to_string(); // "Red"

Clojure:

(name :red) => "red"

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

#47
post #23

Earlier quoted context omitted.

Serialization is the canonical example. Being able to turn struct MyStruct { int val = 42; string name = "my name"; }; into { "val": 42, // if JSON had integers, and comments of course "name": "my name", } is incredibly powerfuly. If reflection supported attributes (i can't believe it shipped without, honestly), then you could also mark members as [[ignore]] and skip them.

You can achieve that since C++20 (or C++17 if you don't care about the member names). E.g. https://www.linkedin.com/posts/vittorioromeo_cpp-gamedev-ref... (The link above shows ImGui generation, but the same exact logic can be applied for serialiation to JSON/YAML/whatever.)

Sure, but

> The magic sauce? Boost.PFR! An incredibly clever library that enables reflections on aggregates, even in C++17.

That's not vanilla C++!

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

#48
post #27
post #23

Earlier quoted context omitted.

Serialization is the canonical example. Being able to turn struct MyStruct { int val = 42; string name = "my name"; }; into { "val": 42, // if JSON had integers, and comments of course "name": "my name", } is incredibly powerfuly. If reflection supported attributes (i can't believe it shipped without, honestly), then you could also mark members as [[ignore]] and skip them.

It is powerful, but I'm not sure it is a good idea. Other languages have it, and there is lots of experience in all the ways things go wrong in the real world. I'm inclined to say you should hand write this code because eventually you will discover something weird anyway.

I disagree. Rust's defacto default is serde, golang comes with batteries included, dotnet/java have had it for _years_, and all the dynamic languages do it.

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

#49
post #47

Earlier quoted context omitted.

You can achieve that since C++20 (or C++17 if you don't care about the member names). E.g. https://www.linkedin.com/posts/vittorioromeo_cpp-gamedev-ref... (The link above shows ImGui generation, but the same exact logic can be applied for serialiation to JSON/YAML/whatever.)

Sure, but > The magic sauce? Boost.PFR! An incredibly clever library that enables reflections on aggregates, even in C++17. That's not vanilla C++!

...so what? It's just a header you have to #include.

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

#50

Earlier quoted context omitted.

It is "cryptic" and "ugly" to you just because you're not familiar with it. You'd pick the macro-based implementation because you are familiar with it. Seeing this argumentation is so tiresome, because it feels like there is a lack of self-awareness regarding what is "familiar" and what isn't, which is subconsciously translated to "ugly" and "bad".

Have you ever used other (modern) programming languages ? In a lot of languages, you achieve the same with 1 line of code. It's not about familiarity, it's about the fact that it's a long and convoluted incantation to get the name of an enum. Why do I have to be familiar with all those weird symbols just to do a trivial thing ? Update: Zig: const Color = enum { red, green, blue }; const name = @tagName(Color.red); //…

C++:

  enum Color { red, green, blue };
  auto name = to_enum_string(Color::Red); // "Red"
Post reply on HN