Yeah, I specifically added the "in Rust" here because I know Zig really cares about this problem. I haven't actually used contemporary Zig enough to be able to say anything about its approach, though.
> Zig's standard library functions that require allocation take the allocator as a parameter, and return oom errors back up to the caller to do with as they please.
You could do something like this in Rust. Here's a function that accepts a vector and pushes something onto it:
fn foo(v: &mut Vec<i32>, item: i32) {
v.push_back(item);
}
(Keeping it non-generic to simplify.)
Does the data structure hold the allocator, or the function? What if I created a list with one allocator, but called push_back with another? It'd have to be in the structure, right? Given that, here's what this feature would look like, roughly, if Vec<T> supported it:
fn foo<A: Allocator>(v: &mut Vec<i32, A>, item: i32) -> Result<(), Box<Error>> {
v.push_back(item)?;
}
This is
significantly more boilerplate. The type signature is more than twice as long! You'd also have to adjust the caller:
// before
foo(&mut v, 5);
// after
foo(&mut v, 5)?;
Of course, it'd be possible to maybe reduce this with langauge features. What does this look like in Zig?