But functions/data structures/whatever can depend on the strategy, and I think that should clearly be communicated.
gpa signals that it does not depend on a strategy. arena signals that it does depend on an arena-like strategy, that is, a resettable allocator. allocator doesnt clearly communicate anything, we just assume it to be analogous to gpa, which I am ok with I just prefer otherwise.
I definitely feel your vibe here. I may have a flaw in my thinking that @vulpesx or another can shed light on⦠Iāll demonstrate with an example below⦠but first:
This makes plenty of sense, and may suggest, again, the āgeneralā nature of using gpa - āā¦does not depend on a strategyā - I read this to mean: the caller might intend to make use of an arena, but another caller might use an actual PageAllocator or whatever, and the lib can handle either.
So, for instance, isnāt something like this āfineā?
const Playlist = struct {
// ...
pub fn deinit(self: *Playlist, al: Allocator) void {
self.deque.deinit(al);
}
pub fn add(self: *Playlist, al: Allocator, song: Song) Allocator.Error! void {
self.deque.pushFront(al, song);
// and do some other stuff with `song` or our own state....
}
};
// ...
// program 1:
{
var fba = FixedBufferAllocator.init(&buffer);
const allocator = fba.allocator();
var my_playlist: Playlist = .init(...);
defer my_playlist.deinit(allocator); // note this!
my_playlist.add(allocator, ...);
// blah blah
} // my_playlist is explicitly deinitialized; deque will free each alloc for each item that was pushFront()ed (or otherwise added)
// program 2:
{
var arena = ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
// ...
{
var my_playlist: Playlist = .init(...);
// note NO my_playlist.deinit() here, intentionally
my_playlist.add(allocator, ...);
// blah blah
}
// some strategic place along the line...
arena.reset(.retain_capacity); // resets playlists (including my_playlist) and anything else built with the arena, all at once, and quickly
{
// some other stuff... another turn of the grist mill, or whatever
}
}
my_playlist.deinit(al) (and thus deque.deinit(al)) were never explicitly called in program 2 because program 2ās strategy was different, and program 1 and program 2 were each happy that they could use their own strategy because Playlist (and Deque, below) are both versatile enough for this.
Perhaps thereās nothing wrong with this code (forgive - I freehanded the code, and Iām still a little mistake-prone), and, at the end of it all, all a pro has to say is: āyeah, fine, but then the convention is to call that thing gpa, not allocator or, worse yet, al (who would use such a stupid name?!). Then, my only comment would be: āfine, but some will perhaps think that gpa might imply that GeneralPurposeAllocator should be used, or that, at least, deinit()should be called to clean-up, because ⦠you wouldnāt want to use an arena, would you?ā I can certainly see where the confusion could come in.
Edit: my_playlist might have more reasonably been declared outside of my little scope curleys⦠but you get the idea.
Havenāt caught up with the entire discussion, so apologies if I am duplicating something already said, but I want to mention that just āarenaā itself is not unary, as there are at least three different semantics that can be powered by arena:
A short-lived scratch space storing intermediate results in a function, which is reset before/just after the function returns
Long-lived āsubsystemā arena which is used to allocate return values for the caller