Live data from Hacker News

Compile-time JSON deserialization in C++

medium.com

61–70 of 89 posts

Re: Compile-time JSON deserialization in C++

#61
post #28

Earlier quoted context omitted.

I was able to do the primitive long double result = 0.0; while (...) { if (json[head] == '.') ... result *= 10; result += json[head] - '0'; } in a constexpr function with no problem :)

The problem with this is that it will not actually parse double in IEEE 754, as you will accumulate inaccuracies at every step of the loop. In theory, when parsing a float, you are supposed to return the floating point that is closest to the original string number. Your code will not do that. Even if you accept the inaccuracy, if you for some reason load the JSON using a runtime library, you'll get different numbers…

Yes, very true. I noticed that even already at 3dp the floats start to compare unequal. The long double helped but it's not really.

I googled and found two examples of constexpr float parsing repositories, but from the sounds of things, you understand this problem better than I and will have seen them already

Re: Compile-time JSON deserialization in C++

#62

Earlier quoted context omitted.

> generate C or C++ instead of having the compile do the same thing much slowly That's a wild-assed guess. A JSON decoder right in the compiler could easily be faster than generation involving extra tool invocations and multiple passes. Also, if you use ten code generators for ten different features in a pipeline instead of ten compile-time things built into the language, will that still be faster? What if most files…

> A JSON decoder right in the compiler could easily be faster than generation involving extra tool invocations and multiple passes. It also can easily be slower: C++ templates are not exactly known for their blazingly fast compilation speed. Besides, the program they encode in this case is effectively being interpreted by the C++ compiler which, I suppose, is not really optimized for that: it's still mostly oriented…

> C++ templates are not exactly known for their blazingly fast compilation speed.

Compared to what alternative that does the same thing, in C++?

Modern C++ compilers, as such, are slow as molasses, on multi-GHz hardware with huge L1 and L2 caches, whether your code uses templates or not.

Re: Compile-time JSON deserialization in C++

#63
post #57

What a beautiful example of abuse of C++ templates. I love it. But please don’t do this in production. What ever you need to do, use C++ templates as the last resort because you’ve figured out all other approaches suck even more. Maintaining template heavy code is absolutely horrible and wasteful (and if it’s C++ production code we measure it’s lifetime in decades). And no, there is no way ”to do it correctly so it d…

This reminds me of some coworkers I had that moaned anytime they saw 'template' in some code. They were convinced that templates were just bad, and that they should stay in the STL. Some of these people would then proceed to use void* and enums to perform the same computations (the C++ haters kind), or use virtual functions all over the place (the java-background kind). Not only was the result much more fragile (compile errors are now runtime errors), but it would also prevent inlining, not to mention the dynamic memory allocation fest.

Re: Compile-time JSON deserialization in C++

#64

Earlier quoted context omitted.

So I have owned a library for 6years or so that does constexpr JSON to data structures, JSON Link. There are a few benefits and in the near future with #embed it gets even better. The big benefit is that we can now get earlier errors and do testing in constexpr that gives more guarantees around the areas of core UB and in most implementations they add constexpr checked preconditions on the std library too. But, just…

Since you've done this for real in a library, I have to ask: how would you decide to use a compile-time template solution like this versus a code generator or some other "outboard" tool to generate code? I'm curious since I've gone back and forth on this in my own career. Both approaches come with their own pros and cons, but each get us to the same place.

I def have more experience with the compile time and it's big issue is how long it can take, but I think it can be overblown on the cost too. However, one can often mitigate this with good code separation and firewalling. The compile time methods will never(probably) be faster than generated code in the C++ compiler. But, a TU with a simple function like `Config parse_config( std::string_view json_doc );` can protect the other code and reduce the general compile time when working on the real code. I think both have their debugging issue with codegen being difficult to tie to the source and the compile time parts relying on the limited error facilities available currently. The proposed p2471 - https://wg21.link/p2471 should help with this a lot and allow for non-literal static_assert messages.

One place I have used the compile time, since JSON Link uses declarative mappings and is type based, is allowing for automatic (de)serialization of function calls over RPC/IPC. This makes things like communicating with web engines really neat, or doing serialized RPC calls over some other mechanism. Code like `server.register( "path", [] ( int x, Foo foo ) { ... } );` is working now in C++, and that's really neat and closely analogues some of the higher level API's in other languages.

Re: Compile-time JSON deserialization in C++

#65

I think the value of compile-time JSON deserialization is... well I was going to say zero but really it's negative. It's a cute trick, but please don't ever do this in a real project.

So I have owned a library for 6years or so that does constexpr JSON to data structures, JSON Link. There are a few benefits and in the near future with #embed it gets even better. The big benefit is that we can now get earlier errors and do testing in constexpr that gives more guarantees around the areas of core UB and in most implementations they add constexpr checked preconditions on the std library too. But, just…

That's a slightly more interesting use case. But "detect data errors at code compile-time via ultra complex comptime template metaprogramming" does not strike me as a particularly good idea. There are much better, easier ways to detect data errors. And the value of baking JSON data into an executable (even if it's transformed) is highly suspect imho.

Re: Compile-time JSON deserialization in C++

#66

I am afraid of the compile-time cost. For this kind of things I tend to prefer using a simpler program (written in anything you like) to generate C or C++ instead of having the compile do the same thing much slowly. Meta programming can be good, but it is even better done with an actual meta program, IMO.

I like how code generation is typically done in Kotlin using KSP. Here you write your code generator as a plugin to the compiler, so you have the full expressivity of any JVM language you like. It also operates on the parsed and resolved AST, so you can analyze even derived types. It also allows code generators to run on code which has type errors or even fails to resolve some symbols which is very useful when you generate code from class annotations and then proceed to use the generated code later in the same file.

Another advantage of using KSP is that it also handles caching for you and will avoid running code generators again if the output already exists.

Re: Compile-time JSON deserialization in C++

#67

Earlier quoted context omitted.

So I have owned a library for 6years or so that does constexpr JSON to data structures, JSON Link. There are a few benefits and in the near future with #embed it gets even better. The big benefit is that we can now get earlier errors and do testing in constexpr that gives more guarantees around the areas of core UB and in most implementations they add constexpr checked preconditions on the std library too. But, just…

That's a slightly more interesting use case. But "detect data errors at code compile-time via ultra complex comptime template metaprogramming" does not strike me as a particularly good idea. There are much better, easier ways to detect data errors. And the value of baking JSON data into an executable (even if it's transformed) is highly suspect imho.

Whether or not this is useful (I am also not sure), the JSON doesn't need to survive into runtime at all. If you include the JSON, do a bunch of `if constexpr`, and never touch the JSON outside of a constexpr context, it doesn't have to any footprint on your binary. (I'm not sure if #embed will force stuff to stay in your binary even if you never reference it at runtime)

Re: Compile-time JSON deserialization in C++

#68
post #67

Earlier quoted context omitted.

That's a slightly more interesting use case. But "detect data errors at code compile-time via ultra complex comptime template metaprogramming" does not strike me as a particularly good idea. There are much better, easier ways to detect data errors. And the value of baking JSON data into an executable (even if it's transformed) is highly suspect imho.

Whether or not this is useful (I am also not sure), the JSON doesn't need to survive into runtime at all. If you include the JSON, do a bunch of `if constexpr`, and never touch the JSON outside of a constexpr context, it doesn't have to any footprint on your binary. (I'm not sure if #embed will force stuff to stay in your binary even if you never reference it at runtime)

That's what I meant by "even if it's transformed". Parsing JSON at compile-time to store in some global variable/constant is highly sus imho.

Re: Compile-time JSON deserialization in C++

#69

Earlier quoted context omitted.

> A JSON decoder right in the compiler could easily be faster than generation involving extra tool invocations and multiple passes. It also can easily be slower: C++ templates are not exactly known for their blazingly fast compilation speed. Besides, the program they encode in this case is effectively being interpreted by the C++ compiler which, I suppose, is not really optimized for that: it's still mostly oriented…

> C++ templates are not exactly known for their blazingly fast compilation speed. Compared to what alternative that does the same thing, in C++? Modern C++ compilers, as such, are slow as molasses, on multi-GHz hardware with huge L1 and L2 caches, whether your code uses templates or not.

The alternative would be to run the JSON through e.g. jq/sed and make it dump out a chunk of C++ that would create an object with proper fields and subobjects. This C++ code will have about zero template chicanery; instead, it would just call constexpr constructors which, I imagine, would be entirely boring — this C++ code will be compiled much faster.

Re: Compile-time JSON deserialization in C++

#70

Earlier quoted context omitted.

> There is another scenario where this is an issue: if this code ends up in a header which is included in a lot of places. This is all on itself a sign that your project is fundamentally broken, but this is already covered by scenario b) incremental builds. Even if for some reason you resist the urge of following best practices and not create your own problems, there are a myriad of techniques to limit the impact of…

Fundamentally broken, or waiting for modules to become a thing? I tried to use https://github.com/mjspncr/lzz3ᵃ for a few years but it became impractical to me to fiddle with tooling. a : You don't have source file and header file, you put everything in one file and lzz sorts it out during build.

https://github.com/mjspncr/lzz3
Post reply on HN