# arraylist `ArrayList` is zig's growable buffer - you use it when you don't know the size upfront. common for building strings, collecting results, or accumulating data before sending it somewhere. in 0.15, arraylist became "unmanaged" - you pass the allocator to each method instead of storing it in the struct. the compiler catches missing allocators immediately, so that's not the tricky part. the tricky part is ownership. ## ownership patterns when you build up data in an arraylist, you eventually need to do something with it. there are two paths: **build and discard** - you use the data, then throw it away. this is most common (e.g., building an http response): ```zig var buf: std.ArrayList(u8) = .empty; defer buf.deinit(alloc); // cleanup when we're done try buf.print(alloc, "{s}: {d}", .{ name, value }); sendResponse(buf.items); ``` `buf.items` is the `[]u8` slice holding the actual data - a direct view into the arraylist's internal buffer. the arraylist still owns this memory, so don't hold onto it after `deinit`. **build and return** - you're building something to give to a caller. they'll own the memory: ```zig var buf: std.ArrayList(u8) = .empty; // no defer here - we're transferring ownership try buf.appendSlice(alloc, data); return buf.toOwnedSlice(alloc); // caller must free this ``` the key difference: `.items` borrows (arraylist still owns the memory, will free on `deinit`). `.toOwnedSlice()` transfers ownership (arraylist forgets about it, caller must free). see: [dashboard.zig#L187](https://tangled.sh/@zzstoatzz.io/music-atmosphere-feed/tree/main/src/dashboard.zig#L187) for the return pattern ## direct methods vs writer you might think you need to get a writer to write formatted output, but arraylist has `.print()` built in: ```zig try buf.print(alloc, "{{\"count\":{d}}}", .{count}); ``` use `.writer(alloc)` when you need to pass to something that expects a generic `std.Io.Writer`: ```zig const w = buf.writer(alloc); try json.stringify(value, .{}, w); ``` ## why unmanaged from the [release notes](https://ziglang.org/download/0.15.1/release-notes.html): storing the allocator had costs - worse method signatures for reservations, can't statically initialize, extra memory for nested containers. the benefits (convenience, avoiding wrong allocator) didn't justify it since the allocator is always nearby anyway.