Hi everyone, I find myself writing self referencing structure quite often and, as far as I know, you have to initialize an instance in two steps in order to preserve pointer addresses.
For example, I want to create a serializer that cache a pointer to a writer so that each methods can access it without putting var writer = self.buffer.writer() at the beginning of each method.
To achieve this, you can’t do that:
const Serializer = struct {
allocator: Allocator,
buffer: ArrayListUnmanaged(u8) = .{},
writer: ArrayListUnmanaged(u8).Writer,
// Doesn't work because we return a local variable, pointers will be invalid
pub fn init(allocator: Allocator) Serializer {
var self = Serializer{ .allocator = allocator, .writer = undefined };
self.writer = self.buffer.writer(allocator);
return self;
}
}
What I result to all the time is defining two methods (but you have to know/document that you need to call the two before using it) like:
I run into that “problem” all the time inside init functions.
If some field-initialization is more than 1 or 2 lines I write an extra (privvate) function to handle it.
But it is kinda inconvenient having to do that. No clean init.
A couple of alternative approaches you may consider is:
allocating the serializer instead of relying on RLS (which tends to be fine if you’re allocating anyway and you already have a deinit). This is a pretty common pattern for these situations.
pass in the writer (or buffer) where needed instead of having it as a field