← Back to context

Comment by glandium

5 years ago

I don't know Zig, but it sounds like Zig allows to use arbitrary allocators for anything. The abstraction Rust is getting will only work for things that do account for using arbitrary allocators. Anything that doesn't will end up using the global allocator. That's a significant difference.

To clarify, it's up to the function being called; the convention set by Zig's standard library is that if a function needs to allocate memory, then the allocator (specifically, a struct of function pointers to an allocator's implementations of realloc and shrink) should be one of the function's arguments.

There is of course nothing stopping a function from ignoring this and using the C global allocator if need be (or, as I've done in some experiments, using a C library's custom allocator - in my case that of SQLite).

(EDIT: from what I understand, there's technically nothing stopping C from using this sort of strategy, either; a struct of function pointers ain't exactly exotic. It's just a matter of libraries being written with that convention in mind, which doesn't seem to be very common.)

  • Oh so it has, in fact, the same caveat as Rust's scheme.

    Edit: I guess the difference is that Zig doesn't have years of not supporting it, making the ecosystem more prone to support it.

  • In a large complex application you are going to want to use the same allocator everywhere, or close to everywhere, and almost all functions may allocate memory directly or indirectly, in which case this Zig convention will require most every function to have a useless parameter. That sounds enraging.

    • A large complex application seems like exactly the kind of environment where being stuck with a single allocator would be enraging. I personally like the idea of being able to give each component of a large system its own fixed chunk of memory (and an allocator over that chunk), such that if one component goes crazy with memory consumption it's isolated to that component instead of choking out the whole system.

      7 replies →

That is being backfilled in; Vec already implements it on nightly, IIRC.

And really, what you're talking about here is "the standard library data structures," which aren't super likely to be used in firmware anyway. It's a lot easier for ecosystem data structures to add support, after all, they already would choose to call the global allocator, so now they can do either. And it is much easier for them to cut backwards-incompatible changes, if they have to.

  • > which aren't super likely to be used in firmware anyway.

    Why not? Zig's std library is specifically designed to be usable for freestanding/baremetal targets (e.g. firmware), and the compiler is smart enough to only include the parts of a library (including std) that are actually used. If you do need to reimplement a part of std, you can just... reimplement that part, and import your own implementation instead of the one from std.

    Unless you're talking purely about Rust?

    • I am talking purely about Rust, yes. Firmware tends to use libcore, and if it does happen to dynamically allocate memory, liballoc. libstd assumes you have an OS, so...

  • I mean, in terms of Rust, it sounds like Zig allows to use any allocator for anything in any crate. Not only structs in std or other crates that explicitly allow a custom allocator. In Rust, and only talking about std, you'd need to change a lot of things to allow e.g. BufWrite, etc. to use a custom allocator. And every crate that uses types that allocate stuff under the hood. But maybe I'm misunderstanding what Zig allows.