Why `self.* = undefined`?

In the standard library, I see this pattern everywhere, for example in BufSet and BitStack:

pub fn deinit(self: *@This()) void {
    self.bar.deinit(); // or other actual freeing of memory
    self.* = undefined; // why?
}

What is the purpose of self.* = undefined here?

The only reason I can think of is to make it easier to spot usages of something that was already deinitialized, as 0xAA is written to undefined in debug mode. Is that truly the only reason?

6 Likes

Some time ago I read the same thing somewhere else in the stdlib (I think, mightve been the same thing) and wondered what it was for. I came to the same conclusion as you.

1 Like

Yes, it makes it easier to detect use after deinitialization errors. The compiler can also use this information for optimizations.

3 Likes

Does it do anything in other modes besides debug?

It informs valgrind and can be used for optimization. So slightly more than just writing over memory in debug/safe. It also communicates that this container is now invalidated and thus may not be used after .deinit(). Mistakes in reusing it result in a likely segfault which can be caught by the runtime in modes where it’s overwritten and explicitly marked UB otherwise.

2 Likes

Outside of debug, it should not emit any machine code, but it could improve the code around it. There’s been a bug where, sometimes, the compiler forgets to remove the write, but I think it’s been solved.

4 Likes

I did not know this idiom. I’ve just been putting stuff in the api docs, but I’ll start using it now. thanks.