If TigerBeetle is the Zig flagship then Zig is untenable for almost any team, because Tiger Style is untenable for almost any team. No, I think that Tiger Style makes Zig mostly unimportant.
On the other hand, as a corporate backer for Zig, TigerBeetle is definitely a big deal.
But in terms of exemplary and imitable projects in the ecosystem I would think something like Ghostty is the safer label for "flagship".
TigerBeetle is interesting because even though something like TigerStyle is unusual for a database, it is very much at home for embedded systems.
In fact we could summarize TigerBeetle as "the financial database developed like embedded software". Determinism is a cornerstone of critical software like in avionics, and naturally, dynamic allocation is forbidden, as in TigerStyle.
So even though it is not obvious, TigerBeetle represents one of Zig biggest strengths: embedded systems.
TigerBeetle has a unique static memory allocation strategy at launch time. It’s a strategy that sidesteps a lot of memory management issues but only works for very specific use cases.
Their success with this strategy isn’t portable to most other projects. I think they really need more traditional flagship projects that generalize to typical memory management use cases. The way the conversation keeps coming back to TigerBeetle as a success story isn’t helpful to anyone trying to evaluate the memory management angle.
I would say the exact opposite, actually - Zig is a language specifically suited for TigerBeetle's all-at-once approach to memory management, and the approach more commonly used in Rust (allocate wherever and whenever) is non-idiomatic in Zig.
TigerBeetle calculates all the memory it needs at startup. It allocates that much memory once. It does not allocate memory dynamically.
This only works for very specific use cases, like a fixed server size where you know exactly how much memory you want to allocate to a process.
It’s not portable to general purpose computing, where it’s expected that apps aren’t allocating the maximum amount of memory they might use at startup. Their memory usage grows and shrinks as you open and close files or as your documents get longer.
> and the approach more commonly used in Rust (allocate wherever and whenever) is non-idiomatic in Zig
Allocating memory as needed isn’t a Rust-specific idiom. Most programming involves dynamic memory allocation.
I don’t think the Zig developers would go as far as saying Zig isn’t a good fit for dynamic memory allocation. If it was that simple this entire debacle could have been written off as “Bun requires dynamic memory allocation by nature, therefore Zig isn’t a good fit”. That’s not what Andrew Kelley is trying to say though.
> This only works for very specific use cases, like a fixed server size where you know exactly how much memory you want to allocate to a process.
So, like, the JVM with its "initial heap size" setting? After reserving that space from the OS on startup, pieces of the space are then handed out by the JVM's internal allocator, where and when needed.
If initial heap size and max heap size are the same, that initial one is the only malloc() call that ever happens. Not as common for desktop software, but a common best practice when deploying JVM applications to servers.
(I think we're perhaps tripping over two different meanings of "allocate" - you can "allocate" in the sense of calling malloc(), and you can "allocate" a piece of that reserved memory to a particular scope/function/object without actually calling malloc.)
> Allocating memory as needed isn’t a Rust-specific idiom.
There isn't such thing as "The JVM", there is a standard with several implementations, which one with their own approach to memory management.
You might be mixing it with the reference implementation for the standard, OpenJDK, and even then, it depends pretty much on which set of configuration parameters are given.
The funny thing is that Rust works perfectly fine with statically preallocated memory. It's not even against its idioms - most code will work with zero changes. In a way, the borrow checker is the perfect tool for this situation, since nothing owns any memory and everything is borrowed from the static allocation.
There's definitely one code change that's needed - you need to override the Allocator being used by standard library containers (or, live without standard library containers) and by any third-party dependencies you have. That feature is not even stable, let alone idiomatic.
Using the allocator interface is only required if you allocate, which in this context you explicitly don't. If you want to use static preallocated memory in Rust, you'd have to use #[no_std] and only have access to the core part of the standard library. On the plus side, this is a very well supported and stable configuration, the core library is still pretty rich, and there's plenty of no_std libraries to choose from in the ecosystem.
I used "most" in the pedantic sense of "just a little bit over 50% if you count individual lines and not whole libraries". Most code doesn't operate on Box, Vec, String etc. directly, and is happy with & and &mut to underlying data. And even when it does, it's usually used for giving static lifetime to data, which is a non-issue here because all your preallocated memory has static lifetime already.
On the other hand, as a corporate backer for Zig, TigerBeetle is definitely a big deal.
But in terms of exemplary and imitable projects in the ecosystem I would think something like Ghostty is the safer label for "flagship".