about things
1# arraylist
2
3`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.
4
5in 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.
6
7## ownership patterns
8
9when you build up data in an arraylist, you eventually need to do something with it. there are two paths:
10
11**build and discard** - you use the data, then throw it away. this is most common (e.g., building an http response):
12
13```zig
14var buf: std.ArrayList(u8) = .empty;
15defer buf.deinit(alloc); // cleanup when we're done
16
17try buf.print(alloc, "{s}: {d}", .{ name, value });
18sendResponse(buf.items);
19```
20
21`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`.
22
23**build and return** - you're building something to give to a caller. they'll own the memory:
24
25```zig
26var buf: std.ArrayList(u8) = .empty;
27// no defer here - we're transferring ownership
28
29try buf.appendSlice(alloc, data);
30return buf.toOwnedSlice(alloc); // caller must free this
31```
32
33the key difference: `.items` borrows (arraylist still owns the memory, will free on `deinit`). `.toOwnedSlice()` transfers ownership (arraylist forgets about it, caller must free).
34
35see: [dashboard.zig#L187](https://tangled.sh/@zzstoatzz.io/music-atmosphere-feed/tree/main/src/dashboard.zig#L187) for the return pattern
36
37## direct methods vs writer
38
39you might think you need to get a writer to write formatted output, but arraylist has `.print()` built in:
40
41```zig
42try buf.print(alloc, "{{\"count\":{d}}}", .{count});
43```
44
45use `.writer(alloc)` when you need to pass to something that expects a generic `std.Io.Writer`:
46
47```zig
48const w = buf.writer(alloc);
49try json.stringify(value, .{}, w);
50```
51
52## why unmanaged
53
54from 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.