Hacker News new | ask | show | jobs
by materiallie 262 days ago
Zig certainly has a lot of interesting features and good ideas, but I honestly don't see the point of starting a major project with it. With alternatives like Rust and Swift, memory safety is simply table stakes these days.

Yes, I know Zig does a lot of things to help the programmer avoid mistakes. But the last time I looked, it was still possible to make mistakes.

The only time I would pick something like C, C++, or Rust is if I am planning to build a multi-million line, performance sensitive project. In which case, I want total memory safety. For most "good enough" use cases, garbage collectors work fine and I wouldn't bother with a system's programming language at all.

That leaves me a little bit confused about the value proposition of Zig. I suppose it's a "better C". But like I said, for serious industry projects starting in 2025, memory safety is just tablestakes these days.

This isn't meant to be a criticism of Zig or all of the hard work put into the language. I'm all for interesting projects. And certainly there are a lot of interesting ideas in Zig. I'm just not going to use them until they're present in a memory safe language.

I am actually a bit surprised by the popularity of Zig on this website, given the strong dislike towards Go. From my perspective, both languages are very similar, from the perspective that they decided to "unsolve already solved problems". Meaning, we know how to guarantee memory safety. Multiple programming languages have implemented this in a variety of ways. Why would I use a new language that takes a problem a language like Rust, Java, or Swift already solved for me, and takes away features (memory safety) that I already have?

14 comments

> memory safety is simply table stakes

Why?

And also, this is black and white thinking, implying that "swift and rust" are completely memory "safe" and zig is completely "unsafe". It's a spectrum.

The real underlying comparison statement here is far more subjective. It's along the lines of: "I find it easier to write solid code in rust than in zig". This is a more accurate and fair way to state the semantics of what you are saying.

Saying things like "rust is memory safe. Zig is not memory safe" is reductionist and too absolutist.

>Why?

Memory bugs are hard to debug, potentially catastrophic (particularly concerning security) and in large systems software tend to constitute the majority of issues.[1]

It is true that Rust is not absolutely memory safe and Zig provides some more features than C but directionally it is correct that Rust (or languages with a similar design philosophy) eliminate billion dollar mistakes. And you can take that literally rather than metaphorically. We live in a world where vulnerable software can take a country's infrastructure out.

[1] https://www.zdnet.com/article/microsoft-70-percent-of-all-se...

If decades of experience shows us anything it is that discipline and skill is not enough to achieve memory safety.

Developers simply aren’t as good at dealing with these problems as they think they are. And even if a few infallible individuals would be truly flawless, their co-workers just aren’t.

I'm not convinced that on average Zig is any less safe, or produces software that is any less stable, then Rust.

Zig embraces reality in its design. Allocation exist, hardware exists, our entire modern infrastructure is built on C. When you start to work directly with those things, there is going to be safety issues. That's just how it is. Zig tries to give you as many tools as possible to make good decisions at every turn, and help you catch mistakes. Like it's testing allocator detecting memory leaks.

Rust puts you in a box, where the outside world doesn't exist. As long as you play by its rules everything will be fine. But it eventually has to deal with this stuff, so it has unsafe. I suspect if Rust programmers went digging through all their dependencies, especially when they are working on low level stuff, they would be surprised by how much of it actually exists.

Zig tried to be more safe on average and make developers aware if pitfalls. Rust tried to be 100% safe where it can, and then not safe at all where it can't. Obviously Rusts approach has worked for it, but I don't think that invalidates Zigs. Especially when you start to get into projects where a lot of unsafe operations are needed.

Zig also has an advantage in that it simplifies memory management through its use of allocators. If you read Richard Feldman's write up on the Roc compilers rewtire in Zig, he talks about how he realized their memory allocation patterns were simple enough in Zig that they just didn't need the complexity of Rust.

To be clear, Rust encourages the development of safe abstractions around unsafe code, so that the concern goes from proportion of unsafe to encapsulation of unsafe. Whether you trust some library author to encapsulate their unsafe is, I think, reducible to whether you trust a library author to write a good library. Unsafe is not all-or-nothing. Thus, as with all languages, good general programming practices come before language features.
That's kind of my point. Because it's isolated and abstracted I wouldn't be surprised if most Rust devs have no idea how much unsafe code is actually out there.

Rust does not want you to think about memory management. You play by its rules and let it worry about allocations/deallocation. Frankly in that regard Rust has more in common with GC languages than it does Zig or C. Zig chooses to give the developer full control and provides tools to make writing correct/safe code easier.

Although not a comprehensive report, people tend to count the source lines of unsafe in a Rust codebase as a metric. Moreover, reputable libraries worth using typically take care to reduce unsafe, and where it is used, encapsulate it well. I don't think you have a substantive point on the matter. Unsafe certainly can be abused, but it's not a bogeyman that people scarcely catch glimpses of. Unsafe doesn't demote the safety of Rust to that of C, or something like that.

Your comments on Rust's philosophy towards memory management are off base. Rust is unlike GC languages, even Swift, in that it makes allocations and deallocations explicit. For example, I know that one approach to implementing async functions in trait objects was rejected because it would've made implicit heap allocations. Granted, Rust is far behind on reified and custom allocators. Rust has functionality to avoid the default alloc crate, which is the part of libstd that does heap allocations, and a library ecosystem for alternate data structures. Rust doesn't immediately give you total access, but it's only a few steps away. Could it be easier to work with? Absolutely. The same goes for unsafe.

>> memory safety is simply table stakes

> Why?

Because it's a stepping stone to other kinds of safety. Memory safety isn't the be-all and end-all, but it gets us to where we can focus other important things.

And turns out in this particular case we don't even have to pay much for it in terms of performance.

> The real underlying comparison statement here is far more subjective. It's along the lines of: "I find it easier to write solid code in rust than in zig".

Agreed! But also how about "We can get pretty close to memory safety with the tools we provide! Mostly at runtime! If you opt-in!" ~~ signed, people (Zig compiler itself, Bun, Ghostty, etc) who ship binaries built with -Doptimize=ReleaseFast

Zig has a pretty great type system, and sometimes languages like Rust and C++ are not great with preventing accidental heap allocations. Zig and C make this very explicit, and it's great to be able to handle allocation failures in robust software.
What's great about its type system? I find it severely limited and not actually useful for conveying and checking invariants.
That is the usual fallacy, because it assumes everyone has full access to whole source code and is tracking down all the places where heap is being used.

It also assumes that the OS doesn't lie to the application when allocations fail.

Zig make allocations extremely explicit (even more than C) by having you pass around the allocator to every function that allocates to the heap. Even third-party libraries will only use the allocator you provide them. It's not a fallacy, you're in total control.
> pass around the allocator to every function that allocates to the heap.

what prevents a library from taking an allocator, saving it hidden somewhere and using it silently?

Nothing, but it would be bad design (unless there is a legitimate documented reason for it). Then it's up to you as the developer to exercise your judgment and choose what third-party libraries you choose to depend on.
authors of the library
Why, are you going to abort if too many calls to the allocator take place?
You can if you want. You can write your own allocator that never actually touches the heap and just distributes memory from a big chunk on the stack if you want to. The point is you have fine grained (per function) control over the allocation strategy not only in your codebase but also your dependencies.
Allocation strategy isn't the same as knowing exactly exactly when allocations take place.

You missed the point that libraries can have their own allocators and don't expose customisation points.

> It also assumes that the OS doesn't lie to the application when allocations fail.

Gotta do the good ol'

  echo 2 >/proc/sys/vm/overcommit_memory
and maybe adjust overcommit_ratio as well to make sure the memory you allocated is actually available.
OS specific hack and unrelated to C.
Your comment was also OS-specific because Windows doesn't lie to applications about failed allocations.
Not at all, rather there is no guarantee that the C abstract machine described on ISO C, actually returns NULL on memory allocation failures as some C advocates without ISO C legalese expertise seem to advocate.
>> Why would I use a new language...

If you are asking that question you should not use a new language. Stick with what works for you. You need to feel that something is unsatisfactory with what you are using now in order to consider changing.

To me the argument is that memory errors are just one type of logic error that can lead to serious bugs. You want a language that reduces logic errors generally, not just memory safety ones, and zig's focus on simplicity and being explicit might be the way to accomplish that.

For large performant systems, what makes sense to me is memory safety by default, with robust, fine-grained levers available to opt in to performance over safety (or to achieve both at once, where that's possible).

Zig isn't that, but it's at least an open question to me. It has some strong safe-by-default constructs yet also has wide open safety holes. It does have those fine-grained levers, plus simplicity and explicitness, so not that far away. Perhaps they'll get there by 1.0?

Logical errors and Memory errors aren’t even close to being in the same ballpark.

Memories errors are deterministic errors with non-deterministic consequences. Logical errors are mostly non-deterministic (subjective and domain dependent) but with deterministic consequences.

> For most "good enough" use cases, garbage collectors work fine and I wouldn't bother with a system's programming language at all.

It's not just about performance, it's about reusability. There is a huge amount of code written in languages like Java, JS, Go, and Python that cannot be reused in other contexts because they depend on heavy runtimes. A library written in Zig or Rust can be used almost anywhere, including on the web by compiling to wasm.

> ...memory safety is simply table stakes these days.

Is there like a mailing list Rust folks are on where they send out talking points every few months? I have never seen a community so in sync on how to talk about a language or project. Every few months there's some new phrase or talking point I see all over the place, often repeated verbatim. This is just the most recent one.

Conspiracy nonsense. GP is advocating for GC languages, not Rust.
It was a joke dude. Relax.

Also, literally the first language he mentioned was Rust, and it's the only one he mentioned that would be in the same class as Zig.

> I am actually a bit surprised by the popularity of Zig on this website

Maybe this just indicates that memory safety is table stakes for you, but not for every programmer on Earth?

> I am actually a bit surprised by the popularity of Zig on this website, given the strong dislike towards Go.

I'm not sure that's true, that there is a strong dislike towards Go on here. Maybe that's just competitors or their zealots creating such a perception. Even if that was the case (it being disliked on here), it would only hold true for this site, and not in general. Go is ranked as a top 10 language by TIOBE (as of October 2025). Rust is ranked 16, Swift is ranked 22, Vlang is ranked 42, and Zig behind it at 43.

> for serious industry projects starting in 2025...

In regards to starting projects with Zig, as long as people are clear that it's still in beta, then they should be fine with accepting the risks that go along with that. It's also fine not to want to use Zig and stick with the language that you are comfortable with. If a person wants to experiment or to see what's available, there are many languages in the "better C" or "C alternative" category.

Yes, we know how to offer memory safety; we just don't know how to offer it without exacting a price that, in some situations, may not be worth it. Memory safety always has cost.

Rust exists because the cost of safety, offered in other languages, is sometimes too high to pay, and likewise, the cost Rust exacts for its memory safety is sometimes too high to pay (and may even adversely affect correctness).

I completely agree with you that we reach for low-level languages like C, C++, Rust, or Zig, in "special" circumstances - those that, for various reasons, require precise control over hardware resource, and or focuses more on the worst case rather than average case - and most software has increasingly been written in high-level languages (and there's no reversal in this trend). But just as different factors may affect your decisions on whether to use a low-level language, different factors may affect your decision on which low-level language to choose (many of those factors may be subjective, and some are extrinsic to the language's design). Of course, if, like the vast majority of programmers, you don't do low-level programming, then none of these languages are for you.

As a long-time low-level programmer, I can tell you that all of these low-level languages suffer from very serious problems, but they suffer from different problems and require making different tradeoffs. Different projects and different people may reasonably want different tradeoffs, and just as we don't have one high-level language that all programmers like, we also don't have one low-level language that all programmers like. However, preferences are not necessarily evenly distributed, and so some languages, or language-design approaches, end up more popular than others. Which languages or approaches end up more popular in the low-level space remains to be seen.

Memory safety is clearly not "table stakes" for new software written in a low level language for the simple reason that most new software written in low level languages uses languages with significantly less memory safety than Zig offers (Zig offers spatial memory safety, but not temporal memory safety; C and C++ offer neither, and most new low level software written in 2025 is written in C or C++).

I can't see a strong similarity between Go, a high-level language, and Zig, a low-level language, other than that both - each in its own separate domain - values language simplicity. Also, I don't see Zig as being "a better C", because Zig is as different (or as similar) from C as it is from C++ or Rust, albeit on different axes. I find Zig so different from any existing language that it's hard to compare it to anything. As far as I know, it is the first "industry language" that's designed almost entirely around the concept of partial evaluation.

Would you say writing something like a database (storage and query engine) from scratch is better done in Rust or Zig?
It depends on the purpose. If the objective is maximum scale and performance then Zig. The low-level mechanics of userspace I/O and execution scheduling in top-end database architectures strongly recommends a language comfortable expressing complex relationships in contexts where ownership and lifetimes are unavoidably ambiguous. Zig is designed to enable precise and concise control in these contexts with minimal overhead.

If performance/scale-maxxing isn't on the agenda and you are just trying to crank out features then Rust probably brings more to the table.

The best choice is quite arguably C++20 or later. It has a deep set of somewhat unique safety features among systems languages that are well-suited to this specific use case.

First, I would avoid using any low-level language if at all possible, because no matter what you pick, the maintenance and evolution costs are going to be significantly higher than for a high-level language. It's a very costly commitment, so I'd want to be sure it's worth it. But let's suppose I decided that I must use a low-level language (perhaps because worst-case behaviour is really important or I may want to run in a low-memory device or the DB was a "pure overhead" software that aims to minimise memory consumption that's needed for a co-located resource heavy application).

Then, if this were an actual product that people would depend on for a long time, the obvious choice would be C++, because of its maturity and good prospects. But say this is hypothetical or something more adventurous that allows for more risk, then I would say it entirely depends on the aesthetic preferences of the team, as neither language has some clear intrinsic advantage over the other. Personally, I would prefer Zig, because it more closely aligns with my subjective aesthetic preferences, but others may like different things and prefer Rust. It's just a matter of taste.

> the DB was a "pure overhead" software that aims to minimise memory consumption that's needed for a co-located resource heavy application)

Thanks pron for the reply. This describes it the best. To minimize resource consumption in a "pure overhead" software. It's currently written in Java and we are planning a rewrite in a systems PL.

I would first spend a good amount of time figuring out if you can't just keep it in Java, because it's not just the rewrite in C++ that's expensive, but a low-level language would make maintenance and evolution costlier forever.

If memory footprint is the issue, I would recommend watching this: https://youtu.be/mLNFVNXbw7I. A lot of people misunderstand memory consumption, and even in Java there are many options to try. There could definitely still be situations where a low-level language is the only choice, but it's not a decision to be taken lightly.

Since most system level api provide a C interface and the c interoperability of zig is top notch you don’t require a marshaling/interop layer.
From what I've seen, it also has much less of an impedence mismatch. You can sling pointers around to your heart's desire in Zig, whereas in Rust you have a lot of sanitization and restructuring when going crossing the barrier.
That's true of Rust as well, so it's not really an advantage unique to Zig.
Is it? Most of the time I read you have to create a wrapper, like here: https://docs.rust-embedded.org/book/interoperability/c-with-...

Please provide some documentation of how to use c libraries without such interop layer in rust. And while bindgen does most of the work it can be pretty tedious to get running.

rust has really high learning curve
Perhaps worse is the fatigue curve that some people claim sets in after a few years of using it.
Do you have links on people’s experience with the fatigue curve?

I’ve heard of “hard to learn, easy to forget” but I haven’t seen people document it for career reasons.

I have no hard data. I have seen comments to this effect in HN. Somewhat famously Primagen threw in the towel on it. I would love to hear from others with 4+ years of Rust experience though.
I think that's mostly async fatigue.

Avoid it and you're good, you just have to accept that a big part of the language is not worth its weight. I guess at that point a lot of people get disillusioned and abandon it whole, when in reality you can just choose to ignore that part of the language.

(I'm rewriting my codex-rs fork to remove all traces of async as we speak.)

That does seem like a lot to give up however if doing any amount of I/O. No?
I guess lack of job positions could be one kind of fatigue curve.
Tried to use Swift outside Xcode and it’s a pain. Especially when writing CLI apps the Swift compiler chocked and says there is an error, mentioning no line number. Good luck with that. Also the Swift tooling outside Xcode is miserable. Even Rust tooling is better than that, and Swift has a multi billion dollar company behind it. What a shame…
None of all those memory-safe languages allows you to work without a heap. And I don't mean "avoid allocations in that little critical loop". I mean "no dynamic allocation, never ever". A lot of tasks doesn't actually require dynamic allocation, for some it's highly undesirable (e. g. embedded with limited memory and long uptimes), for some it's not even an option (like when you are writing an allocator). Rust has some support for zero-runtime, but a lot of it's features is either useless of outright in the way when you are not using a heap. Swift and others don't even bother.

Unpopular opinion: safety is a red herring. A language shouldn't prevent the programmer from doing the unsafe thing, rather it should provide an ergonomic way to do things in a safe way. If there is no such way - that's on language designer, not the programmer. Rust being the worst offender: there is still no way to do parent links, other than ECS/"data oriented" which, while it has it's advantages, is both quite unergonomic and provides memory safety by flaying it, stuffing the skin with cow dung and throwing the rest out of the window.

>strong dislike towards Go.

Go unsolves problem without unlocking any new possibilities. Zig unsolves problem before it aims towards niches where the "solution" doesn't work.

> Rust has some support for zero-runtime, but a lot of it's features is either useless of outright in the way when you are not using a heap.

Could you give some examples?

Genuinely curious because I don't know: when you group Swift with Rust here, do you mean in terms of memory safety guarantees or in the sense of being used for systems-level projects? I've always thought of Swift as having runtime safety (via ARC), not the same compile-time model as Rust, and mostly confined to Apple platforms.

I'm surprised to see them mentioned alongside each other, but I may very well be missing something basic.

Swift is mostly runtime-enforced now but there are a lot of cultural affinities (for lack of a better term) between Swift and Rust and there’s a proposal to add ownership https://github.com/swiftlang/swift/blob/main/docs/OwnershipM...