4 ms·
Yeah, it looks like Zig is a bit overly lazy. As a comparison, what C++ does is that it differentiates between "dependent" and "non-dependent" expressions, whe
by planede 4y ago
Yeah, it looks like Zig is a bit overly lazy.
As a comparison, what C++ does is that it differentiates between "dependent" and "non-dependent" expressions, where "dependent" means that it depends on some template parameter (analogous to comptime parameter here). "non-dependent" expressions are type-checked eagerly, while dependent expressions are only checked at instantiation time.
The design is certainly more complicated, even more so when you consider function overloading and name lookup, which can give different results if done late or early. But there are some upsides, and zig wouldn't need to deal with the additional complications of overloading.
edit: https://eel.is/c++draft/temp.dep https://eel.is/c++draft/temp.dep
- skywal_l 4y agoWell it's basically like C macros. The C compiler won't see any code that's behind a deactivated macro. Same thing for zig here, except you don't have to deal with an unreadable macro language full of pitfalls. All is done in the language itself.
- stephc_int13 4y agoGetting rid of macros (and all of their well documented pitfalls) is good. Getting rid of the preprocessor and conditional compilation may not have been necessary. (as the feature is needed anyway and have to be implemented in a different manner) The thing is that comptime, even if better than macros because everything is written in the same language, might end up not being much better than C macros. Many of the macro pitfalls still applies, if you think about it...
- anonymoushn 4y agoI sort of like that Zig is lazy here, because in C++ a bunch of stuff that works in Zig just doesn't work. In this line[0] a radix sort selects a function to read the next 8 or 16 bits of the input words. The C++ version of this code has to have readOneByte and readTwoBytes take an additional template parameter to control the return type: static constexpr auto readBucket = (BYTES_PER_LEVEL == 2) ? readTwoBytes<idx, udigit> : readOneByte<idx, udigit>; because both parts of the expression are evaluated by the compiler and must be the same type, including the function's return type. This means we end up instantiating nonsense functions like readTwoBytes returning u8. Elsewhere in the same file, some should-be-impossible template instantiations have had to have their static_assert's removed, because C++ will instantiate them and then not insert any calls to them into the generated code. So one cannot use static_assert to say "If this is reachable, that's a bug, please fail compilation and return an error" because template instantiation and the execution of the static_assert does not imply that the function won't be immediately discarded as unreachable. [0]: https://github.com/alichraghi/zort/blob/main/src/radix.zig#L161 https://github.com/alichraghi/zort/blob/main/src/radix.zig#L...
- planede 4y agoThis is a different issue. You could have replaced the ternary with if constexpr in a lambda, but it's very verbose. I saw some people to propose that ternary should work potentially like if constexpr, if the condition is a constant expression. Honestly, IMO the ternary operator is already cursed, and it should not be overloaded with more responsibility. I think this should work without nonsense return types: static constexpr auto readBucket = []{ if constexpr (BYTES_PER_LEVEL == 2) { return readTwoBytes<idx, udigit>; } else { return readOneByte<idx, udigit>; } }();