> Every struct or bare fn now needs (2) fields/parameters by default.
Storing interfaces a field in structs is becoming a bit of an an anti-pattern in Zig. There are still use cases for it, but you should think twice about it being your go-to strategy. There's been a recent shift in the standard library toward "unmanaged" containers, which don't store a copy of the Allocator interface, and instead Allocators are passed to any member function that allocates.
Previously, one would write:
var list: std.ArrayList(u32) = .init(allocator);
defer list.deinit();
for (0..count) |i| {
try list.append(i);
}
Now, it's: var list: std.ArrayList(u32) = .empty;
defer list.deinit(allocator);
for (0..count) |i| {
try list.append(allocator, i);
}
Or better yet: var list: std.ArrayList(u32) = .empty;
defer list.deinit(allocator);
try list.ensureUnusedCapacity(allocator, count); // Allocate up front
for (0..count) |i| {
list.appendAssumeCapacity(i); // No try or allocator necessary here
}
I’m not sure I see how each example improves on the previous (though granted, I don’t really know Zig).
What happens if you call append() with two different allocators? Or if you deinit() with a different allocator than the one that actually handled the memory?