32 comments

[ 2.9 ms ] story [ 52.0 ms ] thread
(comment deleted)
This article works really well to illustrate a question I have: why is Zig so popular in posts here?

For most languages I can usually see one or two “killer features” that push the language: For Rust is taking C space with memory safety + modern semantics, for Go is being easy to learn by most engineers + parallelization, for Ruby is ergonomics…

I don’t see any similar pitch for zig other than a general “I kinda enjoy it”, and the language seems to have a couple red flags, so why focus on it? (Honest question).

It's doing something novel in the systems programming space, and makes a bunch of different trade-offs compared to Rust. That's interesting, even if you might reasonably conclude that Rust is still a better language to use in most cases. It's good to explore different corners of the programming language design space.

Every single commonly-used programming language has a couple red flags, often much more than a couple. Javascript, C, C++, Go, Python - these languages all have serious flaws and are nonetheless used by extremely large numbers of people for all sorts of tasks.

probably should define memory safety before using it as an evaluation criterion

otherwise, not sure who the audience of this piece is supposed to be, but it's written in a pretty combative tone, which will not be persuasive to anyone who isn't already persuaded, so i guess more of a rant than anything worth sharing here

I find a lot of these points persuasive (and I’m a big Rust fan so I haven’t spent much time with Zig myself because of the memory safety point), but I’m a little skeptical about the bug report analysis. I could buy the argument that Zig is more likely to lead to crashy code, but the numbers presented don’t account for the possibility that the relative proportions of bug “flavors” might shift as a project matures. I’d be more persuaded on the reliability point if it were comparing the “crash density” of bug reports at comparable points in those project’s lifetimes.

For example, it would be interesting to compare how many Rust bugs mentioned crashes back when there were only 13k bugs reported, and the same for the JS VM comparison. Don’t get me wrong, as a Rust zealot I have my biases and still expect a memory safe implementation to be less crashy, but I’d be much happier concluding that based on stronger data and analysis.

I had the same thought. But one thing was actually very useful to compare "bug densities": deno vs bun. They have comparable codebase sizes as well as comparable ages (7y vs 4y). I'd like to see the same stats for tigerbeetle, which is very carefully designed: if segfaults were relatively high on that as too, well...
> Don’t get me wrong, as a Rust zealot I have my biases and still expect a memory safe implementation to be less crashy

That is a bias. You want all your "memory safety" to be guaranteed at compile time. Zig is willing to move some of that "memory safety" to run time.

Those choices involve tradeoffs. Runtime checks make Zig programs more "crashy", but the language is much smaller, the compiler is vastly faster, "debug" code isn't glacially slow, and programs can be compiled even if they might have an error.

My personal take is that if I need more abstraction than Zig, I need something with managed memory--not Rust or C++. But, that is also a bias.

> My personal take is that if I need more abstraction than Zig, I need something with managed memory--not Rust or C++

You may potentially like D. Its tooling leaves much to be desired but the language itself is pretty interesting.

The authors section on comptime makes me believe they have not used zig anything non trivial.

I don’t think comptime as just some macro system. It is closer to a reflection system. I use comptime to access types. You can create specialized paths depending on type.

Also imo generics are “first class” in zig. Comptime is first class and thus generics are too.

I have admired many parts of Zig and its philosophy but I've never seen it as a language that I want to use. What I've noticed is that Zig users care most about explicitness, simplicity, and minimal indirection. This leads to a lot of syntax that is cumbersome to read (albeit unambiguous) like casting and a lack of "convenience" features. I can't help but think that maybe they're right and that this philosophy probably leads to better software because nothing is "hidden". But, I also think that there's a level of abstraction/indirection that makes code clearer and less error-prone. It's a tricky balance to achieve, and past languages have succeeded and failed at it to different degrees. Either way, I echo the OP's sentiment: if Zig is your jam, great, go make some awesome stuff with it. It's just not my go-to today.
It really comes down to a matter of opinion where the line between "nothing hidden" and convenience lies. Technically, a loop is an abstraction of convenience that hides the comparative jump underneath.
I think, but I may be wrong, Zig wants to be high level assembly that could replace C. If people are viewing it from Python, Ruby, JS, and then C++ and Java POV, Zig may be a little too "raw". But then I don't think Zig intends to compete with C++ or Java. May be there will be a Zig ++ or Objective-Zig someday that will do that.
> Zig's comptime is a very large and all-encompassing feature that ultimately brings very little to the table that smaller features cannot.

> I am personally a proponent of a good macro system.

Comptime is much more constraint than any macro system: no code generation (including AST rewrite), no arbitrary tokens. Thus it's much harder to "go overboard" with Zig's comptime. This constraints of cource have their drawbacks, but code generation is still a thing.

> Much of Zig seems to me like "wishful thinking"; if every programmer was 150% smarter and more capable, perhaps it would work.

Nice way to put it! But I oppositely believe the world needs more tech that treats professionals as experts, not kids.

> But I oppositely believe the world needs more tech that treats professionals as experts, not kids.

This attitude is why we still have bounds checking memory bugs in new software in 2025.

IMHO an artisan should want superior tools that produce better results.

> But I oppositely believe the world needs more tech that treats professionals as experts, not kids.

This made me think about Rust borrow checker: given the amount of people struggling with it, I would think the number of experts is much lower than I would initially assume.

> But I oppositely believe the world needs more tech that treats professionals as experts, not kids.

Seconded. I've really come to loathe tech that is constantly trying to "help me" unprompted and do things I didn't ask/want it to do or burying settings/configurations if not obfuscating them away entirely and acting as if it's doing me a favor by removing features in the name of "simplicity" or some shit. And let's not forget built-in obsolescence moonlighting with privacy-disrespecting dark patterns masquerading together as "Smart Devices."

Not an expert, but isn't Zig's comptime essentially an AST generator?
Why have I been seeing a Zig post every day for the past week? Is there some kind of a marketing push?
still less than Rust posts.
Advent of code is coming, maybe lots of people looking for a language to learn with it?
It may be due to the async/io changes which may have caused a wave of renewed interest in the language
> Zig does not have a way to iterate through a slice or similar in any way except one-at-a-time forwards. Anything else? You're using a while loop, and you'll enjoy it.

    INCR[U] i FROM 0 TO len(arr) [BY 1] DO ...

    DECR[U] i FROM len(arr) TO 0 [BY 1] DO ...
Although actual BLISS-77 had inclusive semantics for the upper bounds in both forms. Which, on one hand, allows you to write

    DECRU i FROM UINT_MAX TO 0 DO ...
and expect it to Just Work™ (hopefully? No idea if it worked on actual implementation ― but would've been nice, writing the same in e.g. C is kinda annoying; good luck with Golang pre-1.22 and even then, getting that one last iteration is quirky) but on the other hand, inclusive upper bounds require you to write add that "-1" almost everywhere.
It's interesting to see how popular Zig is becoming, I thought it would get overshadowed by Rust and it would go nowhere.
This treatment of memory safety is becoming almost a cargo cult at this point. If this were a binary issue, then clearly Rust wouldn't cut it because it is quite common in Rust (much more so than in, say, Java) to rely on unsafe code. So if you think Rust is good at memory safety, that means that you must believe that some level of unsafety is acceptable. The only question is how much, and what you're willing to pay to reduce it.

The reason we care about memory-safety so much, compared to other invariants we'd like our programs to have is because, as the article notes, a very high portion of vulnerabilities are due to memory-safety violations. This is why preventing or reducing such violations is important in the first place.

But if we look at vulnerability rankings [1][2], we see that Zig's memory safety covers the top weaknesses just as well as Rust, and much better than C. The vast difference in the complexity of these two languages is because Rust pays a lot to also prevent less dangerous vulnerabilities, outside the top 5.

So if Rust is good because it eliminates some very common dangerous vulnerabilities thanks to its memory safety, then Zig must also be good for eliminating the same ones. Calling it C-like because it doesn't eliminate some less common/dangerous vulnerabilities just because Rust does, is just a misunderstanding of why this is all important in the first place. (Plus, if it's important to reduce the security vulnerabilities due to memory safety violations, isn't it better to make avoiding the worst outcomes more approachable?)

In software correctness there are few easy choices. Everything boils down to how much you can and should pay to improve your confidence that a certain level of damage won't occur. It's a complicated subject, and trying to present it as a simple one does it a great disservice.

In fact, both Rust and Zig address some of the most common/dangerous vulnerabilities — more than use-after-free - just as well as C, which is to say, not, or barely, at all. I.e. there are worse vulnerabilities that neither one of them eliminates than the ones Rust eliminates and Zig doesn't.

There is no doubt that Rust and Zig are meant to appeal to people with different aesthetic preferences, but the attempt to distinguish them by turning the matter of memory-safety into a binary one simply doesn't make sense. The property of memory safety is itself not binary in both languages, and the impact of memory safety is split between more and less important effects.

I understand why people wish to find objective metrics to prefer one language over another, but often such metrics are hard to come by, and extrapolation based on questionable assumptions is not really objective.

But if you choose to only focus on security weaknesses, and you choose to ignore the language design's impact on code reviews or the fact that allocations are much more visible in Go than in C (which is not very objective, but perhaps you consider these harder to quantify), you would still have to conclude that there's a big difference - on your chosen metric alone - between Zig and C, and a rather small difference between Rust and Zig.

What I think really happens, though, is that most of the preference boils down to aesthetics, and then we desperately seek some objective measures to rationalise it.

> Much of Zig seems to me like "wishful thinking"; if every programmer was 150% smarter and more capable, perhaps it would work.

But if working harder to satisfy the compiler is something that requires less competence than other forms of thinking about a program, then why Rust? Why not ATS? After all, Rust does let you eliminate more bugs at compile time than Zig, but ATS lets you eliminate so many more. So, if this is an objective measure to reject Zig in favour of Rust, then it must also be used to reject Rust in favour of ATS.

Neither Rust nor Zig are anywhere near either extreme on compile-time guar...

I think a lot of the absolutists around memory safety are just using it as a bludgeon to evangelize their preferred programming language. Otherwise, the position of "memory safety is the most important thing, but we should ignore other languages that provide stronger guarantees" is absurd.
> One extra register is all you ever need, even for an arbitrary parallel move!

This statement, albeit true, is highly misleading. In the example given, you ought to be concerned with parallel assignments not parallel moves. See [0] for more details on the distinction.

[0] https://inria.hal.science/inria-00289709

The author refers to casting ints to floats but seems to actually be talking about converting. Casting is when you change the type, but don't change the data..

I don't really think much of Zig myself for other reasons, but comptime seems like a good design.

> Casting is when you change the type, but don't change the data..

Is that the case? That's not what I think of when I think of C-style casts.

    float val = 12.4;
    int val_i = (int) val;
The representation in memory of `val` should not match that of `val_i`, right? The value is encoded differently and the quantity is not preserved through this transformation. I don't think that means that the data weren't changed.

Maybe you're thinking of aliasing/type-punning? Casts in C do perform conversions as they do in C++.

I find the point about memory safety to be pretty damning.

People think it's a slight on their abilities. "I can write memory safe code!" Maybe you can. There are two huge problems here, and they're problems that will never go away no matter how good you are.

The first is that this doesn't scale. As soon as you add more programmers to a project, you multiply the odds of bugs like this. Even if everyone's just as good, not everyone will have the whole program in their head or code in exactly the same style.

The second is that code rots. Your new C (or Zig) program might be totally correct and memory safe when it's first written. Then you commit it to a repo. Then you move on to another project for a while. Then someone else fixes something and you merge a PR. Then you come back to it three months later and you're under pressure to implement something. Then you work in a new feature a year later and you've forgotten some of the really nit-picky details of how things work. It's very easy over time for bugs to creep in, and if the language doesn't catch them they'll sit in the code until they cause random crashes or, worse, a CVE.

These aren't avoidable issues. They're inherent to software and its life cycle. Memory safe languages (and secure computing systems in general) are the only way to deal with them.

What’s the opposite of damning with faint praise? “Removes many but not all of the C footguns. Self hosted compiler isn’t that much faster than Clang.”