Comment by bunderbunder
20 hours ago
Zig is aiming to be lower level than Rust. As the project homepage prominently advertises, it has no hidden memory allocation or control flow. It also gives more control over how memory is allocated, which is potentially useful in applications with particularly tight performance requirements.
Kelley first created Zig when hr was working on a digital audio workstation and found most existing languages to be awkward for working with particularly hard real time requirements, but still wanted something more modern than C. Im speculating here, but I believe its advantage over Rust for that specific application is that you have tighter control over exactly when memory is allocated and deallocated, and how data is laid out in it. Rust wants to tie allocation lifetimes to scope in a very fine grained way that I would guess is beneficial the vast majority of the time, but does still make it harder to reason about when you’re about to stall out the CPU while the allocator does its thing.
> it has no hidden memory allocation or control flow
Rust had like 3 allocating types total. If you aren't working with extremely deeply nested 3rd party types it's trivial to identify when allocations happen. Hell you could throw a lint rule together in like 5 minutes to warn on it if you're really worried. Besides Drop (excluding async) is there even any hidden control flow?
> Im speculating here, but I believe its advantage over Rust for that specific application is that you have tighter control over exactly when memory is allocated and deallocated, and how data is laid out in it.
Rust has almost exactly the same semantics for controlling allocations and deallocations, it just prevents you from screwing it up and not freeing something or using the allocation after freeing it. You still have to pass around your reference in your call stack until you no longer need it.
> Rust wants to tie allocation lifetimes to scope in a very fine grained way that I would guess is beneficial the vast majority of the time, but does still make it harder to reason about when you’re about to stall out the CPU while the allocator does its thing.
It's really not substantially different. You allocate ahead of time or don't allocate at all. The only real difference is you might want to use an Option instead of an uninitialized pointer because it's semantically more correct and harder to screw up.
But here I feel like we’re at risk of heading down the same old doom spiral that plagues any conversation about programming languages when people try to treat it as a competition: getting pedantic about what’s technically possible in a language. It’s much more interesting to talk about how a language wants to be used.
So, in the case of Zig, every function that wants to be able to allocate or deallocate heap memory needs an explicit reference to an allocator. That means that you can tell whether a function might allocate memory from its signature. It also means that changing a function so that it can allocate is explicitly a breaking change.
That’s a really interesting design decision. And the reasons why someone would or would not want something like that baked directly into the language are so much more interesting than bickering about how technically with proper discipline you can have that kind of control in any non-GC language.
> That means that you can tell whether a function might allocate memory from its signature.
In practice that's not the case, as many objects own a reference to their allocator. It's still explicit, but it might be hidden in the signature, especially if you have some sort of interface that can take an allocating and a nonallocating data structure alike.
I agree with you, but it’s not baked directly into the language? It’s just a convention and a shared trait?
3 replies →
I wish people would stop inventing new languages for nostd when we have nostd
> Rust had like 3 allocating types total.
Seriously? Categories of types maybe, but literal types it's more than that.
Even closures allocate if they need to capture their environment.
It’s actually the opposite: the language has zero allocations in it. Allocation is entirely a library concern.
When you want to have a closure allocate an environment, the closure itself does not: the Box you wrap it in, which is a stdlib type, does.
> Zig is aiming to be lower level than Rust.
Zig and Rust are equivalently "low level". Zig isn't any closer to the hardware than Rust is.
> but I believe its advantage over Rust for that specific application is that you have tighter control over exactly when memory is allocated and deallocated, and how data is laid out in it.
Rust gives you all this, too.
Zig's primary (possibly only) advantage over Rust is that it has much faster compilation times.
Comptime is a big one too. You can achieve similar things in Rust with generics and macros, but comptime makes certain things easier (and other things harder).
.map is definitely not low-level