Don’t you think that making an ad-hoc BoundedArray results in even more verbosity? Certain things that would be an API call turn into multiple lines.
Also, using the same BoundedArray in multiple functions leads to code reuse, with smaller binaries and better cache locality.
Slightly tangential, but I remember seeing in a PR a comment from Andrew saying that the Zig compiler stopped using BoundedArray in favor of ArrayList, because it resulted in better code generation. Anyone could elaborate on this?
I used to have a lot of small arrays with counters as well, but nowadays I’ve almost exclusively switched to allocation and array lists. Of course you need a good (and thread local) allocator for this, but the big advantage for me is that I don’t have to worry about setting the upper limit right.
When you say “constant”, I hear known lower and upper bound which are the same number. If that’s correct, I would use an array personally, there seems to be no downside.
BoundedArray is more for a known upper bound, but where the actual number of elements is runtime-determined. I’ve never had occasion to use one actually, it seems like the idea is that it can use the familiar ArrayList methods but with a stack allocation of constant size?
I’m sure that can be useful, but if I need to store exactly sixteen of something I use a plain-old-array and a separate index. Might be force of habit from other languages but it works.
If you like the ArrayList API better and know you will not add more items than the bounds of the buffer allows, then you can do:
var items: [16]Item = undefined;
var list: std.ArrayListUnmanaged(Item) = .initBuffer(&items);
// ...
// note: do *not* call any ArrayListUnmanaged functions that take an allocator
The original intention with initBuffer was to replace BoundedArray entirely (the PR that added it originally had the title std: remove BoundedArray), but BoundedArray was ultimately kept because it can be used for different use cases (e.g. it allows safe copying).
I personally have need for this type of idea quite a lot in my golang projects, when parsing headers for specific protocols that define a maximum header length (like the Gemini Protocol). I haven’t had a chance to use them in Zig yet, but it seems like it could serve that purpose very well.
Although, now I’m concerned about the performance issues mentioned above.
I’ve had the thought to add similar functions myself. I would nitpick the names though, I think appendNoResize collides with the resize function in an unfortunate way. I think a better name might be appendCheckCapacity, or appendNoAlloc.
Are you thinking of std.io.fixedBufferStream? std.io.BufferedWriter expects to wrap another Writer, where in this case they have a fixed size buffer they want to write into.