You can just do that, and then Zig is really no less robust than Rust. But if you want to do "managed language" style allocation patterns (like what llms generally prefer), it doesn't make sense to use it.
You can just do that, and then Zig is really no less robust than Rust. But if you want to do "managed language" style allocation patterns (like what llms generally prefer), it doesn't make sense to use it.
Grouped allocations works especially well in parsers & ASTs where the lifetime is very bounded. Since the Rust rewrite, we still use arenas for Bun’s parsers and the bundler but not a ton elsewhere.
Not if you use segmented arrays
If you just don't write bugs, then yes all languages are equally robust, including assembly.
Zig, like C, is simply not a robust language. I don't know why this feels like something contentious? It's clearly not intended to be robust?
I don’t think it makes sense to say Zig is or isn’t intended to be robust in general. Like, we don’t say Rust isn’t robust since it doesn’t add dependent types and general purpose static verification that can do more general proofs. It’s focused on eliminating one class of memory bugs in particular, exactly the class of bugs that are the biggest challenge for software like Bun, and other software with complex lifetimes (it originated from Mozilla and Rust is perfect for browsers)
Zig is intended to be robust for software like TigerBeetle, or the Zig compiler itself, where memory lifetimes are simple.
I’d say the focus on built in tests, fuzzing, debug memory allocators and safe mode shows that Zig is absolutely intended to be robust, within the scope of what the language aims to be. Far more than C itself or most of its popular compilers ever did.
Give it a few years! I've noticed an explosion in interest in formal verification recently, especially since nowadays the bar to entry is so low: just ask your LLM agent to give it a go.
Despite TigerBeetle being one of the highest-profile remaining Zig projects, I actually don't think they're representative of the average Zig project at all.
Not a lot of people write programs this way.
"Kelley describes why he created Zig, when other options including C, C++, Rust, and Go already exist. He said he set out to develop a digital audio workstation. He tried Go, but found interoperability with C libraries difficult, and said the garbage collector caused audio delays. He tried C++, or coding C-style using a C++ compiler, but found that small mistakes led to memory corruption bugs that took weeks to fix. He tried Rust but "really struggled to write code that would satisfy Rust's rules," and spent a month trying to make font rendering work."
https://www.theregister.com/software/2026/05/28/zig-creator-...
I've even seen it on some simulation software's core that was written in the 80s originally; at the time memory was much more constrained so allocating upfront meant you could check upfront whether the simulation could actually run or not vs crashing out part way through.
See here for a post on their deterministic simulation harness: https://tigerbeetle.com/blog/2023-07-06-simulation-testing-f...
And I think embedded software is a field where Zig will be at its best. The only thing it is missing is maturity. When project lifetimes are measured in decades and changing a single byte can cost millions, no one in his right mind will pick a language that is still in development. Things will become interesting when it reaches 1.0.
Allocating in large chunks is often not very performant which is why people came up with tools like the borrow checker, you often want to allocate and deallocate dynamically on a need-basis but that's exactly where bugs occur.
Of course you could argue that on average, most programmers are not going to have the right practices and skill, so on average you should prefer Rust. But that's unrelated to the argument I was making, and in any case not a very interesting point in my opinion.
The problem is mostly people graduating from school thinking that somehow there is only stack and heap, and malloc/free is how you do heap. That view completely ignores that the essence of programming systems is mostly to understand the machine, and then doing conceptual and architectural work on a solution (and also on a problem). The act of writing actual code is then mostly just translating those concepts into the digital world verbatim.
"Extraordinary claims require extraordinary evidence" -- Carl Sagan
That's just it, using Zig required more rigorous engineering than the Bun team were capable of.
Who are these "people" you speak of? It's possible to write software in low level languages that don't have these problems. Not a "non-zero" it might be possible, it can be done thoughtfully, and the popular notion it can't be done is backed only by incomplete anecdotes.
Should everything be written in low-level languages? No, that would be absurd. Is it a simple fact of life that not every person/team/organisation is capable of meeting certain standards of rigour? Yes. That's not to say anyone in the Bun team could not become sufficiently competent in the future. For whatever reason, current experience, incentives, and personal motivations did not make for a conducive environment to make Bun watertight in Zig.
Zig does help you. Array slices, explicit nullability of pointers, defer errdefer, explicit allocators, built-in leak detection, bounds checks, overflow detection, the list goes on. If you need to play around on that side of the fence, Zig gives you a lot to make sure you don't mess it up. If we were talking about C I'd give you your flowers, but we're not. The most common issues and vulnerabilities that crop in C from manually managing memory are strongly mitigated by a quarter of that list.
The good news here is that we have more than just anecdotes to support this, we have empirical evidence.
You could write a JS engine with Zig-like idioms (arena allocation, static initialization), but that would require re-writing the whole JS engine from the ground-up (though I would definitely be interested in it if someone actually tries to do it!)
The C++ interop of Swift is perfectly fine, to such a degree that FoundationDB is now using it effectively alongside its C++ origins.
Arena allocators & static initializers are not novel. You'll find them in high performance C++ projects as well, such as LLVM or JavaScriptCore. But arena allocators have the quite significant limitation that they only help when everything being allocated in them have approximately the same lifetime. So they don't help when you need to allocate memory to provide the native implementation of a JavaScript object, for example (eg, FFI).
Could you actually? That seems like a bad fit for a JS engine to me. Predictable memory requirements are great when you can have them, perhaps you can avoid complexity then, but for a JS engine?
I cannot take this seriously as tutorials on robust Zig Allocation Pools will store a deinit method for each item within the pool, so when the pool deinits, all internal objects can be deinit'd.
That is just RAII & dtors from first principles, except with extra overhead of manually storing fat pointers yourself (and the bugs that come with this). Instead of using a language with builtin guarantees & optimizations around handling this so your object pools don't need to carry around a bunch of function pointers. C++ has aggressive de-virtualization passes so at runtime a lot of the 'complex object hierarchies' can be flattened to purely static function calls.
Here I would just like to mention that if you have to rely on "de-virtualization" passes, you're in a miserable situation architecturally. If you have code where the overhead of virtual function calls might be too much to pay, don't do virtual functions then. End of story.
To deconstruct a pool of objects, I don't see what should ever be wrong with a function pointer. The overhead of loading the function pointer will get divided by the number of objects being deconstructed. Care to explain what's the issue here?
1. You're writing code you don't have to
2. That adds runtime overhead
3. That when you screw up has non-trivial security & resource management side effects
This is objectively indefeasible in nearly any vaguely professional context.
2. And the code being compiled is abstract & generic, it won't be instantiated for every type and bloat the executable or instruction cache.
3. Security concerns: With C++ virtual methods every object carries a mutable pointer too (to a vtable containing function pointers). What resource management side effects please?
You claimed there were problems many times for sure, I don't think you came up with any evidence of those problems.
People use them because by default values have scope based lifetimes and destructors unify the handling of stack based values which require no explicit cleanup with data structures that heap allocate, which require no explicit cleanup once the destructor is implemented.
This is the opposite of C where even though the resource cleanup needs to happen on scope end, it is not automatic, and so becomes a source of bugs. This is exaggerated when there are multiple returns, gotos, macros and other sources of branching especially for error handling.
This automation also removes boilerplate so there is less management that needs to be done when using data structures.
What was your evidence or explanation?
I have given a variety of arguments why I think the C++ RAII specifically has downsides. You can accept them or ignore them, but don't act like I didn't give arguments.
> People use them because by default values have scope based lifetimes and destructors unify the handling of stack based values which require no explicit cleanup with data structures that heap allocate,
Once again you're explaining beginner C++ do me. Are you still doubting if I understand this argument? My response to this was and is, if you have primarily stack scoped lifetimes, you are writing beginner programs. This is scripting and plumbing. It's not interesting to me. Systems programming is not so much about stack scoped lifetimes.
RAII systematicing object lifetimes and cleanup, thus enabling exceptions and implicit or uncontrolled control flow, may sound nice on paper, but turns out we shouldn't want them in the first place. What RAII leaves for me is a system that will automatically call nested object's destructors when I delete something. It's not something I want in general, I think it has more downsides than upsides for the code I'm writing. I've actually tried to use RAII many times and I've concluded it doesn't work for me.
> This is exaggerated when there are multiple returns, gotos, macros and other sources of branching especially for error handling.
If I were you, my response would be: The burden of proof is on you, show the evidence. But my answer is, yes that is right, but everything is a tradeoff, and the issues caused by manual cleanup are also somewhat exaggerated by C++ people, and the issues caused by blindly buying into the corset of C++ types are not well understood by C++ zealots (I've done my best at explaining them).
Issues caused by C approach are also a matter of design and approach to programming in general. It also depends on the actual problem you're solving. The linux kernel for example doesn't exactly have the easiest or most beautiful code to follow, but surely it's one of the most technical codebases out there, one that solves difficult problems (performant resource multiplexing for programs that it doesn't even know). On the other hand, the debugger code base I've referenced doesn't have any gotos for example, nor even early returns (or almost none, not sure).
Find me a single example of programs that run as fast and are as productively maintained as these two codebases in their respective areas? I believe there aren't any.
This should be plenty evidence to a reasonable mind, but that isn't you.
I don't think you did, I think you just said it has downsides over and over.
Once again you're explaining beginner C++ do me.
Don't ask for basic knowledge then get upset when you get it.
My response to this was and is, if you have primarily stack scoped lifetimes, you are writing beginner programs.
This is what the vast majority of values have. Some escape one scope and get cleaned up in another one. This also includes values inside data structures.
It's not something I want in general, I think it has more downsides than upsides for the code I'm writing. I've actually tried to use RAII many times and I've concluded it doesn't work for me.
Again, this isn't an explanation, it's just you saying "I don't think it's good, I don't like it", but you aren't explaining why. This isn't evidence, it's just you restating "this is bad". Why is it bad? "I told you it's bad!!".
thus enabling exceptions and implicit or uncontrolled control flow
Exceptions aren't uncontrolled flow and you can also not use them. Something else being enabled doesn't mean the unrelated feature is bad. This also implies that every other language that isn't C is terrible because they have some sort of automatic cleanup. Now java and python are unstructured by your own definition?
If I were you, my response would be: The burden of proof is on you, show the evidence.
You don't have an explanation of why the burden of proof is on me. Everyone uses these techniques in system software now. You are the odd person out, that's why the burden of proof is on you.
I also gave you a very good explanation and you said "you're explaining basic C++ to me". I am, you asked for it and you didn't poke any hole in why it's wrong.
the issues caused by manual cleanup are also somewhat exaggerated by C++ people
It means memory leaks and crashes which everyone has been fighting for 50 years.
This should be plenty evidence to a reasonable mind, but that isn't you.
Someone running a marathon without shoes doesn't mean shoes are bad. Just because an old program is written in C, that has no bearing on if other tools are good or not. This is not a logical conclusion. Unix was written in C too, does that mean destructors are bad? No one said it's impossible to write a program in C now that C++ exists.
Why can't you give a single basic explanation instead of making the same claim over and over?
Show evidence of your claim.
> Don't ask for basic knowledge then get upset when you get it.
Where did I ask for basic knowledge? You are hallucinating. I've repeatedly and explicitly told you to shut up explaining beginner things. You are trying to refute my criticisms of RAII with your silly explanations of how RAII works. That's not how an argument or "evidence" works.
> Exceptions aren't uncontrolled flow and you can also not use them.
I would rather call it _implicit_ flow but they also lead to losing control over control flow because of that. Yes, I can just not use exceptions, and also avoid gotos and use them in a principle way, and do cleanup in a principled way. And then I can also do without RAII and without all the baggage I'd have to buy into in order to use it.
> You don't have an explanation of why the burden of proof is on me.
Please p* off man. You're being ridiculous.
> It means memory leaks and crashes which everyone has been fighting for 50 years.
Like you have been on your Linux, Windows, or Mac machine? Maybe you are running a linux machine with an uptime of weeks, months, or even years?
> Someone running a marathon without shoes doesn't mean shoes are bad.
You claiming to run a marathon with a 25kg backpack doesn't mean you don't lie, and it also doesn't prove running without it isn't the better approach.
> Why can't you give a single basic explanation instead of making the same claim over and over?
The only person not giving explanation beyond basic boring introductory C++ RAII school, that's YOU my friend. I've been giving a lot of explanations what I think is problematic, somehow it seems you're mentally unable to acknowledge them.
Show evidence of your claim.
That would be proving a negative, which is another logical fallacy.
Please p off man. You're being ridiculous.*
If that were true you could explain why.
I would rather call it _implicit_ flow but they also lead to losing control over control flow because of that
But it's just running something you need to run anyway and it's optional. Destructors don't need branching, they can just run a single function like free.
And then I can also do without RAII and without all the baggage I'd have to buy into in order to use it.
Again the "baggage" is the part you can't seem to explain.
Like you have been on your Linux, Windows, or Mac machine? Maybe you are running a linux machine with an uptime of weeks, months, or even years?
Are you trying to say people never write memory leaks or forget to clean up resources in C? Something being done with huge amounts of efforts doesn't mean a better way to do things is bad.
You claiming to run a marathon with a 25kg backpack doesn't mean you don't lie, and it also doesn't prove running without it isn't the better approach.
This doesn't mean anything. Now you're trying to say (without evidence) that someone is lying? Destructors don't add any size to a program.
Is this your only argument after dozens of messages? Running a function with no branching destroys control flow and running a tiny function that runs what you need to call anyway is bloat?
I've been giving a lot of explanations what I think is problematic,
No, you just said it's problematic over and over, that's not an explanation.
"Please give me examples of great systems software written in plain C or C style procedural C++"
"Please give me examples of great systems software written in modern C++, as opposed to procedural C style C++ or plain C".
Why does it seem like the majority of core infrastructure, like Linux kernel (also vast parts of Windows/Mac OS), PostgresQL, Sqlite3, Git, OpenSSH, GCC, but also e.g. MS Office/Excel, are written in plain procedural code and not in modern C++? For the latter, I get stuff like "ScyllaDB NoSQL database" or "Envoy Proxy" or whatever, what is that even and why should I care or how do I know they're actually technically solid products and not just hype?
My claim: The arguments that I've given (but you keep insisting I didn't give them) play a huge rule in why that is so. You can use C++ RAII for plumbing and high-level stuff. But if you try to actually implement technically interesting things, it won't help you at all, it's just getting in the way.
Why don't you do it so you can make your own argument.
Why does it seem like the majority of core infrastructure,
Why are projects started decades not using modern C++ that came decades after they were started?
This doesn't have anything to do with destructors.
The arguments that I've given (but you keep insisting I didn't give them)
You didn't give arguments, you made claims based on other people doing something different decades before modern C++ existed. Someone managing to dig a hole with their hands doesn't make a shovel a bad tool. Animals dig holes all the time, people are better at it.
But if you try to actually implement technically interesting things, it won't help you at all, it's just getting in the way.
This again is your claim which you haven't been able to explain in any way.