9 ms·
Yes! To me, the uniqueness of Zig's comptime is a combination of two things: 1. comtpime replaces many other features that would be specialised in other langu
by pron 2y ago
Yes!
To me, the uniqueness of Zig's comptime is a combination of two things:
1. comtpime replaces many other features that would be specialised in other languages with or without rich compile-time (or runtime) metaprogramming, and
2. comptime is referentially transparent [1], that makes it strictly "weaker" than AST macros, but simpler to understand; what's surprising is just how capable you can be with a comptime mechanism with access to introspection yet without the referentially opaque power of macros.
These two give Zig a unique combination of simplicity and power. We're used to seeing things like that in Scheme and other Lisps, but the approach in Zig is very different. The outcome isn't as general as in Lisp, but it's powerful enough while keeping code easier to understand.
You can like it or not, but it is very interesting and very novel (the novelty isn't in the feature itself, but in the place it has in the language). Languages with a novel design and approach that you can learn in a couple of days are quite rare.
[1]: In short, this means that you get no access to names or expressions, only the values they yield.
- User23 2y agoHas anyone grafted Zig style macros into Common Lisp?
- toxik 2y agoIsn’t this kind of thing sort of the default thing in Lisp? Code is data so you can transform it.
- fn-mote 2y agoThere are no limitations on the transformations in lisp. That can make macros very hard to understand. And hard for later program transformers to deal with. The innovation in Zig is the restrictions that limit the power of macros.
- TinkersW 2y agoLisp is so powerful, but without static types you can't even do basic stuff like overloading, and have to invent a way to even check the type(for custom types) so you can branch on type.
- pjmlp 2y agoNo need for overloading when you have CLOS and multi-method dispatch.
- dokyun 2y ago> Lisp is so powerful, but <tired old shit from someone who's never used Lisp>. You use defmethod for overloading. Types check themselves.
- User23 2y agoAnd a modern compiler will jmp past the type checks if the inferencer OKs it!
- aidenn0 2y agoWhich the inferencer probably can't do because of how dynamic standard-class can be. Also, if we want to get pedantic, method-dispatch does not dispatch on types in Common Lisp, but rather via EQL or the class of the argument. Since sub-classes can be made (and methods added or even removed) after a method invocation is compiled, there is no feasible way in a typical lisp implementation[1] to do compile-time dispatch of any type that is a subtype of standard-object. Now none of this prevents you from extending lisp in such a way that lets you freeze the method dispatch (see e.g. https://github.com/alex-gutev/static-dispatch https://github.com/alex-gutev/static-dispatch), but "a modern compiler will jmp past the type checks" is false for all of the CLOS implementations I'm familiar with. 1: SICL is a research implementation that has first-class global environments. If you save the global-environment of a method invocation, you can re-compile the invocation whenever a method is defined (or removed) and get static-dispatch. There's a paper somewhere (probably on metamodular?) that discusses this possibility.
- User23 2y agoVery interesting comment! To clarify, as you know CLOS isn’t the CL type system. I was particularly thinking about things like fixnum arithmetic. The CMUCL and SBCL manual sections on code generation discuss this and it can be verified with DISASSEMBLE.
- Zambyte 2y agoThere isn't really as clear of a distinction between "runtime" and "compile time" in Lisp. The comptime keyword is essentially just the opposite of quote in Lisp. Instead of using comptime to say what should be evaluated early, you use quote to say what should be evaluated later. Adding comptime to Lisp would be weird (though obviously not impossible, because it's Lisp), because that is essentially the default for expressions.
- Conscat 2y agoThe Scopes language might be similar to what you're asking about. Its notion of "spices" which complement the "sugars" feature is a similar kind of constant evaluation. It's not a Common Lisp dialect, though, but it is sexp based.
- pron 2y agoThat wouldn't be very meaningful. The semantics of Zig's comptime is more like that of subroutines in a dynamic language - say, JavaScript functions - than that of macros. The point is that it's executed, and yields errors, at a different phase, i.e. compile time.
- User23 2y agoYou can do that, I think, with EVAL-WHEN.
- paldepind2 2y agoI was a bit confused by the remark that comptime is referentially transparent. I'm familiar with the term as it's used in functional programming to mean that an expression can be replaced by its value (stemming from it having no side-effects). However, from a quick search I found an old related comment by you [1] that clarified this for me. If I understand correctly you're using the term in a different (perhaps more correct/original?) sense where it roughly means that two expressions with the same meaning/denotation can be substituted for each other without changing the meaning/denotation of the surrounding program. This property is broken by macros. A macro in Rust, for instance, can distinguish between `1 + 1` and `2`. The comptime system in Zig in contrast does not break this property as it only allows one to inspect values and not un-evaluated ASTs. [1]: https://news.ycombinator.com/item?id=36154447 https://news.ycombinator.com/item?id=36154447
- deredede 2y agoThose are equivalent, I think. If you can replace an expression by its value, any two expressions with the same value are indistinguishable (and conversely a value is an expression which is its own value).
- pron 2y agoYes, I am using the term more correctly (or at least more generally), although the way it's used in functional programming is a special case. A referentially transparent term is one whose sub-terms can be replaced by their references without changing the reference of the term as a whole. A functional programming language is simply one where all references are values or "objects" in the programming language itself. The expression `i++` in C is not a value in C (although it is a "value" in some semantic descriptions of C), yet a C expression that contains `i++` and cannot distinguish between `i++` and any other C operation that increments i by 1, is referentially transparent, which is pretty much all C expressions except for those involving C macros. Macros are not referentially transparent because they can distinguish between, say, a variable whose name is `foo` and is equal to 3 and a variable whose name is `bar` and is equal to 3. In other words, their outcome may differ not just by what is being referenced (3) but also by how it's referenced (`foo` or `bar`), hence they're referentially opaque.
- cannabis_sam 2y agoRegarding 2. How are comptime values restricted to total computations? Is it just by the fact that the compiler actually finished, or are there any restrictions on comptime evaluations?
- keybored 2y agoI’ve never managed to understand your year-long[1] manic praise over this feature. Given that you’re a language implementer. It’s very cool to be able to just say “Y is just X”. You know in a museum. Or at a distance. Not necessarily as something you have to work with daily. Because I would rather take something ranging from Java’s interface to Haskell’s typeclasses since once implemented, they’ll just work. With comptime types, according to what I’ve read, you’ll have to bring your T to the comptime and find out right then and there if it will work. Without enough foresight it might not. That’s not something I want. I just want generics or parametric polymorphism or whatever it is to work once it compiles. If there’s a <T> I want to slot in T without any surprises. And whether Y is just X is a very distant priority at that point. Another distant priority is if generics and whatever else is all just X undernea... I mean just let me use the language declaratively. I felt like I was on the idealistic end of the spectrum when I saw you criticizing other languages that are not installed on 3 billion devices as too academic.[2] Now I’m not so sure? [1] https://news.ycombinator.com/item?id=24292760 https://news.ycombinator.com/item?id=24292760 [2] But does Scala technically count since it’s on the JVM though?
- ww520 2y agoI'm sorry but I don't understand what you're complaining about comptime. All the stuff you said you wanted to work (generic, parametric polymorphism, slotting <T>, etc) just work with comptime. People are praising about comptime because it's a simple mechanism that replacing many features in other languages that require separate language features. Comptime is very simple and natural to use. It can just float with your day to day programming without much fuss.
- keybored 2y agocomptime can’t outright replace many language features because it chooses different tradeoffs to get to where it wants. You get a “one thing to rule all” at the expense of less declarative use. Which I already said in my original comment. But here’s a source that I didn’t find last time: https://strongly-typed-thoughts.net/blog/zig-2025#comptime-is-probably-not-as-interesting-as-it-looks https://strongly-typed-thoughts.net/blog/zig-2025#comptime-i... Academics have thought about evaluating things at compile time (or any time) for decades. No, you can’t just slot in eval at a weird place that no one ever thought of (they did) and immediately solve a suite of problems that other languages use multiple discrete features for (there’s a reason they do that).
- WalterBright 2y agoIt's not novel. D pioneered compile time function execution (CTFE) back around 2007. The idea has since been adopted in many other languages, like C++. One thing it is used for is generating string literals, which then can be fed to the compiler. This takes the place of macros. CTFE is one of D's most popular and loved features.
- az09mugen 2y agoA little bit out of context, I just want to thank you and all the contributors for the D programming language.
- WalterBright 2y agoThat means a lot to us. Thanks!
- msteffen 2y agoIf I understand TFA correctly, the author claims that D’s approach is actually different: https://matklad.github.io/2025/04/19/things-zig-comptime-wont-do.html#:~:text=For%20example%2C%20D%20mixins%20work%20that%20way https://matklad.github.io/2025/04/19/things-zig-comptime-won... “In contrast, there’s absolutely no facility for dynamic source code generation in Zig. You just can’t do that, the feature isn’t! [sic] Zig has a completely different feature, partial evaluation/specialization, which, none the less, is enough to cover most of use-cases for dynamic code generation.”
- WalterBright 2y agoThe partial evaluation/specialization is accomplished in D using a template. The example from the link: fn f(comptime x: u32, y: u32) u32 { if (x == 0) return y + 1; if (x == 1) return y * 2; return y; } and in D: uint f(uint x)(uint y) { if (x == 0) return y + 1; if (x == 1) return y * 2; return y; } The two parameter lists make it a function template, the first set of parameters are the template parameters, which are compile time. The second set are the runtime parameters. The compile time parameters can also be types, and aliased symbols.
- deleted 2y ago[deleted]
- baranul 2y agoComptime is often pushed as being something extraordinarily special, when it's not. Many other languages have similar. Jai, Vlang, Dlang, etc... What could be argued, is if Zig's version of it is comparatively better, but that is a very difficult argument to make. Not only in terms of how different languages are used, but something like an overall comparison of features looks to be needed in order to make any kind of convincing case, beyond hyping a particular feature.
- cassepipe 2y agoYou didn't read the article because that's the argument being made (whether you think these points have merit) : > My understanding is that Jai, for example, doesn’t do this, and runs comptime code on the host. > Many powerful compile-time meta programming systems work by allowing you to inject arbitrary strings into compilation, sort of like #include whose argument is a shell-script that generates the text to include dynamically. For example, D mixins work that way: > And Rust macros, while technically producing a token-tree rather than a string, are more or less the same
- baranul 2y agoThe comment made by me, is a reply to another reader, not of the article directly. The push back was on the nature of their comment. > the uniqueness of Zig's comptime... > You can like it or not, but it is very interesting and very novel... While true, such features in Zig can be interesting, they are not particularly novel (as other highly knowledgeable readers have pointed out). Zig's comptime is often marketed or hyped as being special, while overlooking that other languages often do similar, but have their own perspectives and reasoning on how metaprogramming and those type of features fit into their language. Not to mention, metaprogramming has its downsides too. It's not all roses. The article does seek to make comparisons with other languages, but arguably out of context, as to what those languages are trying to achieve with their feature sets. Comptime should not be looked at in a bubble, but as part of the language as a whole. A language creator with an interesting take on metaprogramming in general, is Ginger Bill (of Odin). Who often has enthusiasts attempt to pressure him into making more extensive use of it in his language, but he pushes back because of various problems it can cause, and has argued he often comes up with optimal solutions without it. There are different sides to the story, in regards to usage and goals, relative to the various languages being considered.