Comment by the_duke

5 years 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.

> 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.

  • > 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

    Unless you're talking about some other restriction I'm not aware of.

    • In 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.

    • That 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.

      24 replies →

Zig'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.

  • Hacker news has a really hard time valuing simplicity. I think it’s an egotistical thing: I’m smart so I don’t need a simple language.

    What people miss is that a simple a language allows you to apply your smarts to solving the actual problems in front of you instead of puzzling over language features. You can only handle so much cognitive load at once, and ideally the vast majority of that should be devoted to whatever problem you’re solving, not to the language itself.

    Ironically, this fact is the same fact that makes complex languages more fun for hobbyists. There’s simply more to explore, and to try, and to solve, when your object isn’t building a product but instead playing with a language. It’s a different purpose, but people very rarely acknowledge this fact, likely because they’d rather pretend their purposes are clearly mechanical and business oriented. It’s ok to just want to have fun sometimes.

    • That's an interesting observation.

      It definitely has merit. I've run into this exact same thing in type-system heavy languages like Haskell/Scala/Rust, where I spend more time juggling abstractions than implementing features.

      But there is an additional dimension: abstractions often make the first implementation much more cumbersome. But most code is maintained and read much more than it is written, and abstractions can make extending and maintaining a code base much easier.

      It's also good to remember that the existence of certain language abstractions doesn't mean you have to use them.

      You have to find the right tradeoff.

      2 replies →

    • In all programming languages you must understand how the parser will understand and translate what you write, it sounds like Zig will always know your intentions and maximize your code, it sounds too good to be true

      3 replies →

  • As 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.

    • Which 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.

      5 replies →

  • As the language evolve and people will want to do actual things with it, features will be added.

    • Assumption 1: people don't actually use Zig.

      Assumption 2: the more we do with a language, the bigger the language has to be.

      I am sceptical about (1), and the only way (2) can possibly be true is if the standard library is part of the language (which it really is not: it's user space stuff, curated approved by whoever's in charge). Don't be excessively pessimistic. It's just as irrational as misguided optimism.

      2 replies →

  • > Zig is revolutionary in that its simple partial evaluation construct replaces generics/templates, typeclasses/concepts/traits, macros and conditional compilation.

    This is what C++98 did, except they called their one true comptime evaluation construct "templates", and they did it by accident. There's a reason why Rust introduced generics and typeclasses separately: C++98 templates as bespoke comptime evaluation was a disaster, and this was clear already in the C++ community.

    • > This is what C++98 did, except they called their one true comptime evaluation construct "templates", and they did it by accident.

      Right, except not at all, because templates' syntactic elements are distinct from the "object" part of the language, so it is not a partial evaluation construct for C++, but rather a separate (and rather complex) meta-language for C++. In Zig there is just Zig (with its superb error reporting mechanism), and comptime partially evaluates it. Zig distances itself from C++'s problematic design much more than Rust, which, when all is said and done, is pretty darn similar to C++.

      But that's the problem with revolutionary design. Your ability to compare it to what came before it is limited because it isn't really similar to anything. Luckily, Zig can be fully learned in a day or two, so there's no need to rely on comparisons for long. You can quickly learn it and decide if it's your cup of tea or not; even if it isn't, you'd have learned something quite refreshing and inspirational, and without spending too much time.

      I do agree that there is something more mysterious about Zig. Nobody knows how "good" Rust is yet, either, but it's probably no worse than C++ when we factor all elements that matter to C++/Rust developers, and we're willing to accept that it's also probably not drastically better, except maybe when it comes to undefined behaviour. Zig is more of an unknown because it is so different. It has the potential to be worse than C++, but it can also be much better. At the very least, it is very interesting in that it offers a completely new vision for how low-level programming could be done.

      10 replies →

The approach to arbitrary compile-time execution seems like a particularly novel feature.

  • D, 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).

    • One subtle but extremely important feature of Zig's comptime is that is emulates the target architecture. Fundamental for implementing correct cross compilation.

      1 reply →

    • Zig'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."