9 ms·
How on earth does zig resolve types before macros? Must be some ~~nuts~~ novel order of evaluation to get that behavior. How is this intended to function? Are t
by nukem222 2y ago
How on earth does zig resolve types before macros? Must be some ~~nuts~~ novel order of evaluation to get that behavior. How is this intended to function? Are there multiple layers of macros? Do you have to declare said level or is it derived? How do you use macros to define types or declare types of variables? Can you use said types in other macros?
- pfg_ 2y agoZig doesn't have macros, it has functions which can be run at comptime. You can make a function that returns a type and call it from another function. All declarations are only analyzed when they are first used, and functions when called at comptime are memoized based on their arguments. The order of evaluation is really simple and predictable.
- nukem222 2y ago> Zig doesn't have macros, it has functions which can be run at comptime You raised my hopes and dashed them quite expertly, sir. Bravo!
- gliptic 2y agoYou're probably underestimating what you can do with these.
- weinzierl 2y agoJust for completeness: Rust has functions which can be run at comptime as well. They are called const fn and Rust has them out of the box, no crate required. They are also true Rust and not macros with a separate syntax. They are still not an adequate substitute for Zig's comptime feature. For one and in a sense they are much more limited than comptime functions in Zig but for another (and for better or worse) they also have much higher aspirations than Zig. const fn must always be able to be run at compile time or run time and always produce bit-identical results. This is much harder than it looks at first glance because it must also uphold in a cross-compiling scenario where the compile time environment can be vastly different from the run time environment. This requirement also forbids any kind of side effect, so Rust const fn are essentially pure functions and I've heard them called like that.
- kzrdude 2y agoRust has compile time environment variables and const fns can parse them. It's one very nice and easy way to experiment with or configure rust code at compile time, and should be explored more.
- Zambyte 2y agoReading environment variables contradicts my mental model of pure functions. Are they just not pure functions then? Or pure-ish?
- kzrdude 2y agoThe functions are pure but they take an input from a built-in (looks like a macro) that reads the environment variable at compile time. Also, you only compile once, so how could you tell the difference? You could say - if it was using const fn that it's a "templated" function that depends on compile time settings.
- Zambyte 2y agoI see, I guess if you can't set environment variables during build time that makes it pure-ish enough.
- vlovich123 2y agoYou can set environment variables in your build.rs / the user sets it like A=b cargo build.
- dwattttt 2y agoThere's two lookups that can occur, distinguishing them makes it clearer. Looking up the value of an environment variable at runtime is not a const operation, and produces an error if you try to do it in a const fn. Looking up the value of an environment variable during compile time _can_ be done in a const context, but it'll only happen once. The environment should be considered an input to a const fn, and that makes it "pure". EDIT: These two operations can both be done in non-const functions too, they're different functions (well, one's a macro).
- wavemode 2y agoThe answer is that zig doesn't have macros (i.e. syntactic transformations). Comptime functions in zig are just that - functions which run at compile time. They run after typechecking of existing types, but they are capable of creating new types. Types in Zig are just values. But they're values that don't exist at runtime.
- deredede 2y agoZig's comptime is not macros, it's staged programming / multi-stage programming.
- Ygg2 2y agoZig comptime is a C++ template done better. It also suffers from similar issues as C++ templates. You can't know function is comptime unless you put it in comptime and it passes. See https://typesanitizer.com/blog/zig-generics.html https://typesanitizer.com/blog/zig-generics.html
- pjmlp 2y agoC++98 templates done better, we are past that now in C++23. Also D and Circle, done it before Zig.
- andrepd 2y ago>we are past that now Jesus, we very much aren't. The only real step improvement was in C++11 which added constexpr which (in the following years) gradually obviated the need for C++98 style TMP. But there really hasn't been much of a generational improvement since (OK, concepts I guess), and it remains cumbersome and error prone and difficult to debug.
- pjmlp 2y agoIf I compare C++98 template metaprogramming with tag dispatch, ADL, and SFINAE, with what C++23 offers, it is already a complete different world, even if there are still warts to improve.
- samatman 2y agoThis blog post is disqualified from any serious discussion, because it doesn't know the distinction between templates, which Zig's comptime constructs are not, and partial evaluation with reified types, which Zig's comptime constructs are. It's not possible to make a positive contribution after a mistake that basic. Here's an example of someone getting the design space correct, and therefore contributing to the discussion in a positive way. He doesn't end up liking Zig, for reasons I disagree with, but he does completely evade being not-even-wrong, which is table stakes. https://hirrolot.github.io/posts/why-static-languages-suffer-from-complexity.html https://hirrolot.github.io/posts/why-static-languages-suffer...
- littlestymaar 2y agoThis isn't a macro, it works as both macros and templates in C++, and regarding types it works the same way as templates in C++.
- SkiFire13 2y agoI'll leave this here, try guessing what this prints: const std = @import("std"); const myType = struct { const info = @typeInfo(myType); const before = info.Struct.decls.len; pub usingnamespace (if (before == 0) struct { pub fn baz() void {} } else struct {}); const after1 = info.Struct.decls.len; const after2 = @typeInfo(myType).Struct.decls.len; }; pub fn main() void { std.debug.print("Hello, {} {} {}!\n", .{ myType.before, myType.after1, myType.after2 }); }
- throwawaymaths 2y agowell i suppose this is a good part of the reason why usingnamespace is likely to go the way of the dodo, though if i had to guess: hello: 4, 5, 5