10 ms·
What do you find radical about Zig? I like Zig, but can't see anything particularly revolutionary about it's design. The features mostly an evolution of conce
by the_duke 6y ago
What do you find radical about Zig?
I like Zig, but can't see anything particularly revolutionary about it's design.
The features mostly an evolution of concepts found in languages like D or Nim.
Between the two, Rust is much more revolutionary. Although Rust, of course, was also heavily inspired by research languages that came before.
There's very little happening in CS that hasn't already been conceptualized in the 50-70ies.
- skohan 6y agoThe approach to arbitrary compile-time execution seems like a particularly novel feature.
- lasagnaphil 6y agoD, Nim, and Haxe had it for quite some time (Along with Jai, which is yet unreleased to the public), although you can argue that Zig’s implementation is conceptually the simplest (it has merged compile time semantics with generic types in a unified way).
- Rochus 6y agoAnd Lisp since even a much longer time.
- pron 6y agoI see some abstract aesthetic similarities between Zig and Lisp, or some Lisp's at least -- especially their minimalism -- but Zig's partial evaluation (comptime) works nothing at all like Lisp's syntactic macros (there is no quoting construct, and you don't manipulate syntactic terms at all), and, in fact, has much simpler semantics. The result is intentionally weaker than macros -- macros are "referentially opaque" while comptime is transparent[1] -- but Zig's realisation is that you don't need macros -- with their complexities and pitfalls -- to deliver everything a low-level language would need. [1]: I.e. if x and y have the same meaning ("reference"), in Lisp -- and in any other language with macros -- you could write a parameterised expression e, such that e(x) does not have the same meaning as e(y); you can't do that in Zig.
- Rochus 6y agoThanks. I'm not familiar with Zig. I responded to the "arbitrary compile-time execution" by adding Lisp to the proposed list of D, Nim, and Haxe. Also the latter might raise some concerns when looking at details as you did with Lisp.
- kazinator 6y agoFor instance, even if x and y have the same meaning, (let (x) ...) and (let (y) ... ) will not. So if you can't do that in Zig, that implies you can't write a custom binding construct.
- pron 6y agoA let expression isn't parameterised by x and y but binds their meaning, and the bound variable isn't free in the expression, and you can't substitute it at all. A simple example is an expression that prints the syntactic name of its argument. You can do that in C, C++, Lisp and Rust, but not in Zig (this is OK, because Zig obviates the need for that with excellent backtraces). But this means that you can understand all Zig code as simple Zig code, and that there is no complex meta-language with super-powers as there is in all those other languages I mentioned.
- kristoff_it 6y agoOne subtle but extremely important feature of Zig's comptime is that is emulates the target architecture. Fundamental for implementing correct cross compilation.
- elcritch 6y agoThat's pretty impressive. It's always annoying to get bit struct alignment issues. :/
- pron 6y agoZig's revolution is not in adding a partial evaluation feature, but in removing many other separate features that can be expressed as mere applications. As Antoine de Saint-Exupery said, "Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."
- pron 6y agoZig's main feature is what it doesn't have, and the languages you mentioned don't have that feature. Other languages also have more-or-less general partial evaluation constructs, but they're not revolutionary because they didn't realise they can express traditional constructs in terms of partial evaluation. Zig is revolutionary in that its simple partial evaluation construct replaces generics/templates, typeclasses/concepts/traits, macros and conditional compilation. The result is something that is consistent, extremely powerful, and yet exceptionally simple.
- the_duke 6y agoAs mentioned in my other (wall of text) comment, that's not strictly beneficial. It forces you to implement a lot of logic in "userspace" that other languages do for you automatically. Complexity for certain abstractions moves from the language to user code, at the expense of consistency, cohesion, totality and (auto-generated) documentation. It will be interesting to see how things play out for Zig once the ecosystem grows a little and libraries appear, but there are very significant downsides to this approach.
- deleted 6y ago[deleted]
- pron 6y agoWhich of those is more beneficial indeed remains to be seen and might end up being purely a matter of personal taste; the very thing you call a downside I see as an upside. I think that talking about the positives "consistency and cohesion" where composing primitives works as a positive is merely a matter of habit. Zig treats some aspects that other languages sees as primitives as if they were any other part of the language, where code and libraries rule rather than a growing collection of primitives. I do agree that in principle a language could be too unstructured for some domains (Lisp?) but interestingly, Zig didn't go as far as syntax macros, whereas Rust did. Anyway, Zig finds a surprising middle-ground that is, as yet, hard to definitively judge, whereas Rust, for better or worse, is more of the same.
- 6y ago
- yellowapple 6y ago> What do you find radical about Zig? Personally, I find the "bring your own allocator" philosophy to be pretty radical. Yeah, other systems programming languages can facilitate additional allocators beyond "the" allocator for the language's runtime, but Zig seems to optimize for that case, which makes it a lot more intuitive from a learning perspective (no more guessing about where the memory lives). Even Rust (last I checked) defaults to assuming some global one-size-fits-all allocator. There's also Zig's flavor of compile-time code / metaprogramming. It's probably less powerful than Rust's macros, but I feel like it's a lot cleaner and intuitive, and I'd argue that being able to run ordinary Zig code at compile time is powerful enough of a feature for Zig's use cases. Ultimately, it's a nice happy medium between full-blown metaprogramming (like in Lisp and - from what I understand - Rust) v. preprocessing (like in C/C++). And yeah, I'm sure there's plenty of prior art for everything that Zig does, but I don't know of any other languages that combine these things in such a simple and intuitive and principle-of-least-astonishment-friendly way Zig does.
- leshow 6y ago> Even Rust (last I checked) defaults to assuming some global one-size-fits-all allocator. You can substitute whatever allocator you want: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html Unless you're talking about some other restriction I'm not aware of.
- slimsag 6y agoIn Zig, you can provide a different allocator for a single data structure (or even distinct instances of the same data structure). There is no "global" allocator (what Rust lets you swap out.) This is vastly more powerful, I have used this to tailor an allocator to specific data structures for better performance.
- steveklabnik 6y agoThat is what they're referring to, it is a single global allocator, rather than a per-data structure or per-instance one. You can do this in Rust, there's just no abstraction for it. One is coming.