13 ms·
I love the logo, it is brilliant. Making Rust's macros easier is laudable. Purely from a user's perspective I find it especially annoying, that proc macros nee
by weinzierl 2y ago
I love the logo, it is brilliant.
Making Rust's macros easier is laudable. Purely from a user's perspective I find it especially annoying, that proc macros need their own crate, even if I understand the reasons for it.
If I read Crabtime correctly it solves that problem, which is nice.
That being said Crabtime looks more like compile time eval on steroids to me than an analogon to Zig's comptime.
One (maybe the) distinguishing feature between comptime in Zig and Rust macros seems to me to be access to type information. In Zig you have it[1]
in Rust you don't and that makes a big difference. It doesn't look like we will get that in Rust anytime soon and the projects that need it (e.g. cargo semver check) use dirty tricks (parsing RustDoc from the macro) to accomplish it. I did not see anything like that in Crabtime, but I might have missed it. At any rate, I'd expect compile time reflection for anything that claims to bring comptime to Rust.
[1] I think, but I am not a Zig expert, so please correct me if I am wrong.
- nukem222 2y agoHow 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.
- 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
- pjmlp 2y agoThat is what I really like about the evolution of metaprogramming in C++. While it started as a hack on how to use templates back in C++98, it has gotten quite usable nowadays in C++23, and the compile time reflection will make it even better. All without having another language to learn about, as it happens with Rust macros, with its variations, or reliance on 3rd party crates (syn).
- msk-lywenn 2y agoHow is C++'s template metaprogramming not another language inside C++ today? AFAIK, the syntax and even general logic is still extremely different than regular C++
- Voultapher 2y ago[flagged]
- pjmlp 2y ago[flagged]
- Voultapher 2y ago[flagged]
- tzwhaG 2y ago[flagged]
- pron 2y ago> One (maybe the) distinguishing feature between comptime in Zig and Rust macros seems to me to be access to type information. In Zig you have it[1] in Rust you don't and that makes a big difference. There are other differences. First, comptime functions aren't syntactic macros. This makes them much easier to reason about and debug. You could think about them as if they were regular functions running at runtime in a partially-typed language with powerful reflection (their simplicity also means they're weaker than macros, but the point is that you can get very far with that, without taking on the difficulties associated with macros). Second, I think that comptime's uniqueness comes not from what it does in isolation, but that it makes other language features redundant, keeping the entire language simple. This means that with one simple yet just-powerful-enough feature you can do away with several other features. The end result is that Zig is a very simple language with the expressivity of far more complicated languages. That on its own is not super unusual; in a way, JavaScript is like that, too. But Zig does it in a low-level language, and that's revolutionary. It is because of its simplicity that people compare Zig to C, but it's as expressive as C++ while also being safer than C++, let alone C. Adding comptime to an already-complex language misses out on its greatest benefit.
- forks 2y agoWhat are some examples of other language features that comptime makes redundant?
- dhruvrajvanshi 2y agoIt's generic system for example, is built on top of comptime. A generic struct is just a function that takes a type as an argument and returns a struct. ``` fn Vec(comptime T: anytype) { return struct { // ... } } ``` IMO having a first class generic type parameter syntax is better but this demonstrates OP's point.
- Wumpnot 2y agoIt just looks like C++ templates with a slightly different syntax ..