Zig doesn't instantiate anything the doesn't get called. So, it doesn't have to generate a whole bunch of templated functions and then optimize down to the ones that actually get used.
The upside is that if you only call a generic function with a u32, you don't instantiate an f32 as well. The downside is that when you do decide to call that function with an f32, all the comptime stuff suddenly gets compiled for the f32 and might have an error.
In practice, I feel that I gain way more from the fast compile than I lose from having a path that accidentally never got compiled as my unit tests almost always force those paths to be compiled at least once.
> it doesn't have to generate a whole bunch of templated functions and then optimize down to the ones that actually get used.
It's been a long time since I've dealt with templated C++, but I thought this was how C++ does it too.
C++ will only generate functions for template parameters that are actually used, because it compiles a version of the templated function for each unique template parameters.
C++ is at the very least less lazy than Zig. As an example, if you write some constexpr expression that evaluates a ternary and instantiates a function differently in the two prongs, both will be instantiated, even the one that doesn't end up in the final program. Yes, there are workarounds, but I didn't end up using them. I just moved the offending assert from compile time to runtime because this particular code was not that important.
But the question is if that's actually decisive in the slow compilation problem. The solution in an eager language for evaluating too much stuff is basically "more if statements". Same thing in C++ metaprogramming, use more "if constexpr". If that's all it took to fix C++ compile times, it would have been done a decade ago. The actual problem is all the stuff that you do actually use that has to get repeatedly inlined and optimized away for zero cost abstraction to work.
C++ monomorphises generics on demand too. That's why it can have errors specific to specialization and why template error messages spam long causal chains.
C++ compile times are due to headers. Which in case of templates result in a lot of redundant work then deduplicated by the linker.
The upside is that if you only call a generic function with a u32, you don't instantiate an f32 as well. The downside is that when you do decide to call that function with an f32, all the comptime stuff suddenly gets compiled for the f32 and might have an error.
In practice, I feel that I gain way more from the fast compile than I lose from having a path that accidentally never got compiled as my unit tests almost always force those paths to be compiled at least once.