Live data from Hacker News

TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

tigerbeetle.com

181–190 of 213 posts

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#181
jorangreef: Could you elaborate on what aspects of Zig made it the preferred choice for TigerBeetle compared to C++? I understand the C type system has limitations.

I’m particularly interested as I’ve encountered similar challenges with intrusive data structures in my own work.

This isn’t intended as flamebait. I’m trying to understand Zig’s long-term positioning and design philosophy. I have serious confusion about the type of problems Zig is aiming to solve. In my view, Zig is not solving the actual hard problems in systems programming and it doesn't have the foundation to either.

Memory safety? Still entirely manual. Race conditions? Nothing in the language prevents them. There’s no ownership model, no lifetime analysis, no way to tie resource management to the type system. Compare that to Rust’s borrow checker or modern C++’s RAII and concepts. Zig’s type system is shallow. comptime is nice for generating code, but it doesn’t give you formal guarantees or expressive power for invariants, safety, or correctness.

The type system itself has no serious formal grounding. It can’t encode complex invariants, can’t track aliasing, can’t enforce concurrency safety and can’t model safe resource lifetimes. These aren’t academic extras — they’re exactly what decades of research in programming languages, operating systems and concurrent computing tell us you need to scale safety and correctness. Zig ignores them. Performance? When the policy is in the type (allocator choice, borrowing/ownership, fusion shape), Rust/C++ compilers can specialize, inline, and eliminate overhead. In Zig, the same policies are usually runtime values or conventions, which means more indirect calls, more defensive copies and fewer whole-program optimizations.

Concurrency is another major gap and in a real systems language, it cannot be an afterthought. Even if Zig isn’t currently aiming to solve concurrency or safety, a “serious” systems language inevitably has to, because these are the problems that determine scalability, maintainability and security over decades. The async model in Zig is little more than manual coroutine lowering: the compiler rewrites your function into a state machine and leaves correctness entirely to the programmer. There’s no structured concurrency, no safe cancellation, no prevention of shared-state hazards. Without a concurrency model that integrates into the type system, you can’t make guarantees about thread safety or race freedom and you end up relying entirely on discipline (which doesn’t scale).

Even in its most-touted features, Zig seems to be solving syntactic sugar problems, not the important systems problems. defer and errdefer? They’re effectively cleaner syntax for patterns C has had for decades through GNU’s __attribute__((cleanup)) or macro-based scope guards. Error unions? A nice alternative to out-parameters but just syntactic polish over an old idea. comptime? A more integrated macro system but still aimed at reducing boilerplate rather than providing deeper correctness guarantees.

The allocator interface? Another missed opportunity. Zig could have made it type-aware, preventing allocator misuse and catching entire classes of errors at compile time. Instead, it’s basically malloc/free with slightly cleaner function signatures. No safety net, no policy enforcement.

Zig discards decades of research in type systems, concurrency models, safety guarantees, and memory management, then reimplements C with a few ergonomic wins and leaves the hard problems untouched. It’s a restart without the research and not systems language evolution.

I am not a Rust fanatic but by contrast if you’re moving away from C++ or C, Rust actually tackles the big issues. It enforces memory safety without a garbage collector, prevents data races in safe code through its ownership and type system, offers structured concurrency with async/await and has been battle-tested in production for everything from browser engines to operating systems to databases. It is built on decades of progress and integrates those lessons into a language designed to scale correctness and performance together.

In my own code (primarily C++ and Rust), Zig wouldn’t solve a single core problem I face. Memory safety would still be my responsibility, concurrency would still be entirely manual, performance tuning would remain just as challenging and the type system wouldn’t catch the subtle bugs that matter most. The net result would be cosmetic changes paired with fewer correctness guarantees. Even C, for all its flaws, is better defined than Zig (both in having a detailed, standardized specification and in benefiting from partial formalization).

I am eager and optimistic that Zig starts taking itself seriously as a systems language. With new talent, deeper engagement with existing research and a focus on solving the actual hard problems, not just smoothing over C’s syntax, Zig could grow into something much more than it is today. But until then, the question remains: what problems is Zig actually solving that make it worth adopting over Rust or even modern C++? What concrete systems programming problems has Zig’s development team personally run into that shaped its design and are those really the most critical issues worth addressing in a new systems language?

If all it offers is nicer syntax over the same old pitfalls, I don’t see it and I don’t see why anyone betting on long-term systems software should.

What am I missing?

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#182

Earlier quoted context omitted.

Zig has been great. If anything we could merge critical features (e.g. io_uring, @prefetch builtin and others) into Zig in days or hours instead of years. In hindsight, Zig exceeded expectations, and the quality was exceptional to begin with.

Somewhat of a tangent - did you ever feed "forced" into io_uring because zig lacked native async io? I know you already pre-allocate, and I guess io_uring is effectively pre-allocating a core to doing io work since you have to spin it

Regardless of language, there was never any question that TB would be using io_uring—the interface is that good! If anything, Zig made it easier, bringing all the primitives/atomics I needed to merge io_uring directly into the std lib.

Note that io_uring doesn’t require a pre-allocated core for spinning. There are multiple modes. We just use the kernel thread pool, which we prefer to a user space thread pool!

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#183
post #134

Earlier quoted context omitted.

Why is 90% enough?

I don't think you understand what he saying. Rust is 100% memory safe in specific places yes, but much less so when you have to dip into unsafe Rust. Unsafe memory access will always exist, you can't do anything about it. If you need to interact with the underlying system it's just something you have to deal with it. Zig on the other hand isn't 100% safe in any one part, but it's 90% safe in nearly all parts. Zig rec…

How is Zig considered “90% safe”? It relies on manual memory management, its simple type system provides limited compile-time guarantees and it lacks a mature concurrency model (making safe parallelism difficult). Given these gaps, I struggle to see how Zig achieves a consistently high level of safety. It seems no safer than using AddressSanitizer at best?

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#184

jorangreef: Could you elaborate on what aspects of Zig made it the preferred choice for TigerBeetle compared to C++? I understand the C type system has limitations. I’m particularly interested as I’ve encountered similar challenges with intrusive data structures in my own work. This isn’t intended as flamebait. I’m trying to understand Zig’s long-term positioning and design philosophy. I have serious confusion about…

Was this a question or a statement? :) (I appreciate both, let me add!)

But sincerely, I think we don’t share the same philosophy:

End to end correctness of software is a systems design problem, not a language problem.

I believe that if you try to shoehorn too much safety into a language (100% vs 90%) you get into trouble, and don’t solve safety end to end, like we try to do in TigerBeetle, systematically through TigerStyle, Deterministic Simulation Testing of the system as a whole etc.

I try to write about much of this in the post, to share our ideas, but it comes down to power-to-weight ratio, Zig’s essential simplicity, and recognizing (and coming to terms with) the fact that:

No language can solve end to end systems safety. For this you need systems thinking.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#185

jorangreef: Could you elaborate on what aspects of Zig made it the preferred choice for TigerBeetle compared to C++? I understand the C type system has limitations. I’m particularly interested as I’ve encountered similar challenges with intrusive data structures in my own work. This isn’t intended as flamebait. I’m trying to understand Zig’s long-term positioning and design philosophy. I have serious confusion about…

Was this a question or a statement? :) (I appreciate both, let me add!) But sincerely, I think we don’t share the same philosophy: End to end correctness of software is a systems design problem, not a language problem. I believe that if you try to shoehorn too much safety into a language (100% vs 90%) you get into trouble, and don’t solve safety end to end, like we try to do in TigerBeetle, systematically through Tig…

It's a bit of both! I’d love feedback from someone more experienced with Zig, especially if there’s any flaw in my reasoning here.

The programming language is part of the system design. The abstractions, invariants and guarantees the language provides define what classes of bugs are even possible to have. For example, Rust’s ownership and lifetime semantics eliminate entire categories of memory and concurrency errors that would otherwise surface as “system-design” issues in C or Zig.

When you say “power to weight ratio”, could you elaborate on how that applies relative to C++ in the context of TigerBeetle? You mentioned io_uring support being added. What makes Zig uniquely suited for that compared to a more mature language like C++, which already offers a concurrency model and a sophisticated type system you can selectively use?

You also mentioned prefetch support. That's a lot easier to implement in other languages. I’m curious what specifically made Zig the better fit for these optimizations in your experience.

I appreciate you taking the time to respond to my question.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#186

Earlier quoted context omitted.

I don't think you understand what he saying. Rust is 100% memory safe in specific places yes, but much less so when you have to dip into unsafe Rust. Unsafe memory access will always exist, you can't do anything about it. If you need to interact with the underlying system it's just something you have to deal with it. Zig on the other hand isn't 100% safe in any one part, but it's 90% safe in nearly all parts. Zig rec…

How is Zig considered “90% safe”? It relies on manual memory management, its simple type system provides limited compile-time guarantees and it lacks a mature concurrency model (making safe parallelism difficult). Given these gaps, I struggle to see how Zig achieves a consistently high level of safety. It seems no safer than using AddressSanitizer at best?

Zig makes a lot of small choices that pile up to push you towards safety/correctness in your code.

No hidden allocations is a big one. If something allocates you have to explicitly give it an allocator. This makes tracking allocations much simpler. Combined with the test allocator you can also detect memory leaks.

Allocators also simplify memory management patterns. For example, it's trivially ease to use an arena. Then all your little allocations can be freed all at once, eliminating the need to track each individual allocation/free.

The defer keyword allows you to place the free call near the allocation (same with other resources that require closing). This isn't always possible of course, but it is a lot of the time and makes it easier to track.

Bounds checking is another big one. While loops/for loops with capture groups means you'll basically always see Zig programs iterating through arrays/slices in a manner that ensures you can't go out of bounds.

In terms of general correctness you have explicit nullability. If something can be null you have to mark it as such directly in the type. Then when accessing it you have to unwrap it and deal with the null case.

Same for errors. If something can return an error it's indicated in the return type. The error has to be unwrapped and then thanks to tagged unions you have to deal with all the different possible cases.

There are language conviences like the try keyword that let you side step some of the explicit handling, but even those are easy to track. And you know you're doing something that might bite you.

All of that adds up with a dozen other design choices to produce a language that makes it a lot easier to produce correct code.

Edit: In terms of concurrency I have to give you that one. The language is still pre 1.0 so we'll have to see what happens.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#187

Earlier quoted context omitted.

Was this a question or a statement? :) (I appreciate both, let me add!) But sincerely, I think we don’t share the same philosophy: End to end correctness of software is a systems design problem, not a language problem. I believe that if you try to shoehorn too much safety into a language (100% vs 90%) you get into trouble, and don’t solve safety end to end, like we try to do in TigerBeetle, systematically through Tig…

It's a bit of both! I’d love feedback from someone more experienced with Zig, especially if there’s any flaw in my reasoning here. The programming language is part of the system design. The abstractions, invariants and guarantees the language provides define what classes of bugs are even possible to have. For example, Rust’s ownership and lifetime semantics eliminate entire categories of memory and concurrency errors…

Glad to hear!

Let me invert our roles!

What are 3 of some of the hardest correctness problems in TigerBeetle—and how does TigerBeetle solve them?

Hint: None of these would be solved by language.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#188

Earlier quoted context omitted.

It's a bit of both! I’d love feedback from someone more experienced with Zig, especially if there’s any flaw in my reasoning here. The programming language is part of the system design. The abstractions, invariants and guarantees the language provides define what classes of bugs are even possible to have. For example, Rust’s ownership and lifetime semantics eliminate entire categories of memory and concurrency errors…

Glad to hear! Let me invert our roles! What are 3 of some of the hardest correctness problems in TigerBeetle—and how does TigerBeetle solve them? Hint: None of these would be solved by language.

I don't know. I don’t doubt that TigerBeetle’s hardest correctness challenges can’t be solved by language alone. TigerBeetle has impressive guarantees! Those are inherently systems-design problems.

But the language defines the failure surface and the cost of getting those systems problems right. Likewise, the difficulty and performance of implementing correctness mechanisms (lock-free data structures, concurrent logs or safe async I/O) are directly shaped by the language’s semantics and toolchain.

So while I agree end-to-end correctness is a systems-design problem, the language choice determines how much of that correctness is enforceable, how much is manual and how hard it is to make the right design fast and reliable.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#189

Earlier quoted context omitted.

unsafe exist for that very reason. There's no Rabbi out there to mandate that your code is kosher, using unsafe is OK. Also, the situation where you really need it are rare in practice (in 9 years of full time Rust, I've yet to encounter one ).

Using "unsafe" for things that really need it structurally is incredibly unwieldy and makes all your code a total mess. A single instance of "unsafe" is clean and fine, but if you want or need to use patterns that do not follow the religious "single ownership known at compile time" dogma, you end up spewing "unsafe" in a lot of places and having terribly unclean code as a result. And no, "Arc" is not a perfect soluti…

> Using "unsafe" for things that really need it structurally is incredibly unwieldy and makes all your code a total mess. A single instance of "unsafe" is clean and fine, but if you want or need to use patterns that do not follow the religious "single ownership known at compile time" dogma, you end up spewing "unsafe" in a lot of places and having terribly unclean code as a result.

It's only “unclean” because you see it that way. In reality it's no more unclean than writing C (or Zig, for that matter).

> And no, "Arc" is not a perfect solution to ths because its performance is terrible.

There's no “perfect solution”, but Arc in fine in many cases, just not all of them.

> I encourage you to write a doubly linked list in Rust if you want to understand what I mean about "un-kosher" code

I've followed the “learning rust by writing too many linked lists” tutorial ages ago, and I've then tutored beginners through it, so I'm familiar with the topic, but the thing is you never need to write a doubly linked list IRL since it's readily available in std.

> this kind of pattern is unavoidable if you actually need to interact with hardware

You need unsafe to interact with hardware (or FFI) but that's absolutely not the same thing.

> I have probably written the unsafe keyword several hundred times despite only having to use Rust professionally for a year.

If it's not a hyperbole, that's a very big smell IMHO, you probably should spend a little bit more time digging into how to write idiomatic rust (I've seen coworkers coming from C writing way too much unsafe for no reason because they just kept cramming their C patterns in their Rust code). Sometimes, unsafe is genuinely needed and should be used as a tool, but sometimes it's not and it's being abused due to lack of familiarity with the language. “Several hundreds times” really sounds like the latter.

Re: TigerBeetle and Synadia pledge $512k to the Zig Software Foundation

#190

Earlier quoted context omitted.

Glad to hear! Let me invert our roles! What are 3 of some of the hardest correctness problems in TigerBeetle—and how does TigerBeetle solve them? Hint: None of these would be solved by language.

I don't know. I don’t doubt that TigerBeetle’s hardest correctness challenges can’t be solved by language alone. TigerBeetle has impressive guarantees! Those are inherently systems-design problems. But the language defines the failure surface and the cost of getting those systems problems right. Likewise, the difficulty and performance of implementing correctness mechanisms (lock-free data structures, concurrent logs…

More precisely, “TigerBeetle’s hardest correctness challenges can’t be solved by language AT ALL”.

The “harder problems” in TigerBeetle then (and where we invested millions literally in engineering):

- distributed system strict serializability (cf. our Jepsen audit)

- storage fault safety (TB expects disks to write/read to/from the wrong location, or drop writes entirely, and MUST survive this, all while preserving strict serializability and maximizing availability given the redundancy at hand—it’s one of the first databases in the world that can solve this to these tolerances, cf. “Protocol-Aware Recovery for Consensus-Based Storage”)

I will leave the third one to you! :)

But C++ (or even writing TB in a memory safe language like JavaScript—to reduce the point to absurdity) would have done nothing to solve the hundreds of distributed system bugs our simulators (and TigerStyle methodology) find, ~none of which are language bugs.

Again:

Distributed systems end to end correctness is a systems design problem, not a language problem.

What do we want from our language then?

Power to weight ratio, literal power over the metal (e.g. no OOM or hidden allocations or copies), with essential simplicity in syntax, and explicitness in everything.

I know of no better language for TigerBeetle in this than Zig.

But to make the point more strongly, I don’t think we would have succeeded as a project and company if we hadn’t picked Zig.

C/C++/Rust I feel almost certainly would have cost more, but also would not have given the same quality in terms of design and what I wanted to explore in TigerStyle. It simply would not have been TigerBeetle. We truly needed Zig to exist, and I’m glad it did at the time we needed it.

Post reply on HN