> For example, how would you use a Vec using stack memory for elements, instead of the heap? For the equivalent data structure in Zig (std.ArrayList), it's just a matter of using a stack allocator instead of using a heap allocator, which is an explicit decision either way.
In Rust it would likewise "just" be a matter of using the allocator we want. In this specific case we can see that's nonsense - there's a single stack pointer in the CPU so while it's perfectly possible to make two growable arrays (Vec or ArrayList depending on the language) on the heap, if we use the stack instead they're both obliged to somehow share that single stack pointer when growing, thus whether Zig or Rust this idea can't actually work, but for examples which do work the Rust and Zig doesn't look that different.
Welcome to the magic of Zig, where ideas that can't actually work actually do work :-)
const std = @import("std");
pub fn main() !void {
var not_heap_memory: [1024]u8 = undefined;
var fixed_buffer_allocator = std.heap.FixedBufferAllocator.init(¬_heap_memory);
const allocator = fixed_buffer_allocator.allocator();
var my_list = std.ArrayList(i32).init(allocator);
defer my_list.deinit();
// notice the try! allocation may fail!
try my_list.append(1);
try my_list.append(2);
for (my_list.items) |d| {
std.debug.print("{}\n", .{d});
}
}
The value here is not that you have unbounded stack memory - obviously. The value is that you can use the same API for a growable list (std.ArrayList) backed by stack memory, as you would for a growable list backed by heap memory. This could be useful if you have a function that accepts an ArrayList as an argument and will append to it, but you have a known maximum size for the ArrayList in the context that you're using it. You cannot use the standard Vec type in the same way in Rust. You cannot use any data structures from the Rust standard library that do allocations in the same way.
Yes, of course, you can make data structures that accept custom allocators in the same way in Rust. Maybe there are even community libraries that do it already. The problem is that because they're not in the standard library, you're going to have a hard time using those data structures with any other community libraries. And thus, in practice, you have less control over your allocation strategies in Rust than you do in Zig.
> The problem is that because they're not in the standard library, you're going to have a hard time using those data structures with any other community libraries.
No, all the Rust standard library collections do in fact have the same feature, you can in fact Vec::new_in(SomeAllocator) - my guess is that you'll say "Ah, but that's not yet in stable Rust" and that'd make sense in other contexts but it's a weird objection when the entire Zig language still isn't 1.0.
If you wanted to write a function which takes a container and adds things to it, which I wouldn't recommend, in Rust you'd write that as a polymorphic function, so it'll just get monomorphized for the SomeAllocator variant.
The use of FixedBufferAllocator here is absurd, indeed it's hard to think of non-absurd uses for this allocator, it's a toy because it has no reclamation.
ArrayList has a slightly weird variation on the 1.5x growth pattern, for a large T the ArrayList<T> will grow something like 1, 2, 4, 7, 11, 17, 26, etc. But with your 1024 byte FixedBufferAllocator, the older sizes are just discarded so somewhere around 62 or so items it'll blow up, all the rest of the space was just thrown away and so the growth fails
Overall this not only doesn't do what you said you were doing originally (it's not actually a stack† allocated growable array, those simply don't exist), it also doesn't do the thing you ostensibly claim it's useful for either, so much of Zig feels like this.
† Edited: For a few minute this said "heap" due to a thinko
In Rust it would likewise "just" be a matter of using the allocator we want. In this specific case we can see that's nonsense - there's a single stack pointer in the CPU so while it's perfectly possible to make two growable arrays (Vec or ArrayList depending on the language) on the heap, if we use the stack instead they're both obliged to somehow share that single stack pointer when growing, thus whether Zig or Rust this idea can't actually work, but for examples which do work the Rust and Zig doesn't look that different.