> > which is that over time, as program changes and evolves over years, things tend to drift toward the more general mechanisms that rely on malloc/free on an individual objects, and the program gets slower and slower
I think the idea is that a small program can organize its allocations and data structures to minimize number of calls to malloc, e.g. with preallocated workspace structs, or slab allocation, and similar approaches. But as a program gets bigger, there's a pressure to have looser coupling, to have subsystems with simple convenient APIs which leads to them doing on-demand malloc calls internally, rather than having consumers pre-allocate their needed workspace. Because that kind of workspace management results in more complex APIs and more burden on the consumer.
That said, I don't really believe it either, at least for the kind of codebase where it would matter (scientific computing, in-memory DB server, etc). A codebase that places an emphasis on minimizing heap operations in hot codepaths can do so by consistently using workspaces and allocation-avoiding APIs. I don't think it's so difficult really, but it does take a conscious design decision to do so. But writing something like a web browser in this way could be annoying due to most data having wildly variable sizes, and zig's arena concept would be very handy -- but rust has crates like bumpalo for that purpose.
My personal mantra: "Think in FORTRAN, code in Rust/Julia/C++". But I'm mostly working on HPC-style code where I don't have to do with wildly varying input or output sizes.
> but rust has crates like bumpalo for that purpose.
Except that's not composable - not only do you need specialised data structures, but all (transitively) allocating calls need to be specialised. That's the exact same issue we have in C++, and that's the issue Zig seeks to address. BTW, just the other day there was a post here about a language with another interesting approach, but I have yet to give it a close look: https://github.com/aardappel/goose/
> But I'm mostly working on HPC-style code where I don't have to do with wildly varying input or output sizes.
There you have it. The problems arise more quickly in concurrent rather than parallel code, and when there are lots of features added over the years that touch the hot paths.
> in-memory DB server
Actually, here there can be big problems (as it's also about concurrency rather than parallelism). Last week a colleague of mine looked at Moka and saw that it could only offer half the throughput as Java's Caffeine at the same latency and RAM footprint (almost; the Java program used 5% more RAM). When he looked into it, he saw that over 40% of the program's CPU was spent on the epoch-based reclamation.
> not only do you need specialised data structures, but all (transitively) allocating calls need to be specialised
Most crates for containers will be written such that the container types take an optional allocator type parameter that defaults to the global allocator. You can set it and it transparently uses the other allocator.
To improve the ergonomics, you'd define local aliases that use that allocator.
When that is the case (and it isn't yet; and remember that it's not only the containers, and strings, that need to be parameterised, but any routine that allocates them, transitively), then that's what Zig does. But the question was doesn't Rust solve memory management already, and this is an important aspect it clearly doesn't solve just yet.
i find it fascinating how big of a rust hater you are. willing to outright lie to make your point
It would be helpful if you named the falsehood for those of us following along.
because you can do this
there is nothing stopping you from using custom allocators with your own code or with calls to thirdparty dependenciesbut custom allocators are rarely used in rust because they're simply not needed the vast majority of the time. if your language is not memory safe and you need to manage memory yourself, they're more important. but this isn't the case with rust.
c and zig folks are obsessed with arena allocators particularly because they can group lifetimes of individual objects, reducing the amount of malloc/free calls and thus the amount of use after free, double free, nullptr derefs, or leaks that can occur.
in rust this isn't a concern so custom allocators are only used for performance reasons.
but it turns out that in performance sensitive areas, you generally use custom data structures or those that already have their own allocation strategy baked in, like the generational_arena crate.
most of the time you are not calling thirdparty crates that allocate in performance-sensitive regions. either the crate is designed for this usecase and already uses a performant allocation strategy, or you're writing your own code here.
and in the rare case, you can trivially vendor the crate and pass your own allocator into it, or toggle the global allocator for callers.
but you also need to benchmark first before choosing an allocation strategy because it's not clear that a custom allocator will always guarantee better performance anyways.
and btw zig doesn't guarantee this anyways. you could pull in a dependency that instantiates their own allocator. at least in rust almost all crates use the global allocator as a default which lets you swap it out. if a zig dependency uses their own allocator the only recourse is to fork it.
rust doesn't have a performance problem, so any claims about it's custom allocator support leading to poor performance is unfounded. and thus so are claims about the superiority of zig's approach to allocators.