# Which arguments for deinit (or other invalidating functions)?

**URL:** <https://ziggit.dev/t/which-arguments-for-deinit-or-other-invalidating-functions/10782>\
**Category:** Explain\
**Tags:** language, standard-library\
**Created:** [July 2, 2025, 5:40am UTC](https://ziggit.dev/t/which-arguments-for-deinit-or-other-invalidating-functions/10782 "2025-07-02T05:40:50Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![jbe](https://ziggit.dev/letter_avatar_proxy/v4/letter/j/f6c823/32.png) [@jbe](https://ziggit.dev/u/jbe)\
**Post date:** [July 2, 2025, 9:53am UTC](https://ziggit.dev/t/which-arguments-for-deinit-or-other-invalidating-functions/10782/2 "2025-07-02T09:53:43Z")

</div>

I wonder: Maybe the distinction between `deinit(self: Self)` and `deinit(self: *Self)` depends on whether during the procedure of “deinitializing”, it is helpful to temporarily modify the data structure throughout the process?

But isn’t that an implementation detail that shouldn’t be reflected in the interface visible to the caller of the function? And then again, it has implications for `self.* = undefined` (which might be unnecessary anyway?).

Maybe I’m overthinking, but [as I read earlier](https://ziggit.dev/t/when-to-use-a-struct-vs-a-struct-pointer/10757/13), Zig’s philosophy ([Zen](https://ziglang.org/documentation/0.14.1/#Zen)) suggests there should be:

> - Only one obvious way to do things.

So it would be helpful to have some sort of rule or indication when to use which for `deinit` (and other functions that invalidate a data structure).

**Now the following is just a thought-experiment / brainstorming:**

Would it be (in theory) justified to have a language feature for arguments that are deinitialized? Something like `deinit(deinitialize x: Self)`. The compiler would then know that the passed argument will be considered unusable after the function returned. Or, from the point of view of the caller, already be unusable _right after the function is called_ (i.e. when it starts executing). The compiler could then decide on its own whether to pass the argument by value or by reference. But perhaps we have something like this in the language already? What about:

```zig
pub fn deinit(noalias x: *Self) void {
    // …
    x.* = undefined;
}

```

Due to the `noalias` keyword, the caller would have to guarantee to not use the memory from the moment when the `deinit` function is called (which seems reasonable), and the compiler could then, in the spirit of Parameter Reference Optimization (PRO), decide on its own whether it will pass `self` by value or by reference.

Currently, this doesn’t seem idiomatic at all though. But I’m curious if my thoughts are just nonsense, or if they make sense to some extent?

Also, these hypothetical considerations aside, it still would be helpful to have some rule-of-thumb at hand, which way to go. (Maybe such advice could change in future though, e.g. due to [#1108](https://github.com/ziglang/zig/issues/1108)).

* * *

**Update:**

I did some more research, and found two issues on GitHub in that matter:

- Proposal [#6322](https://github.com/ziglang/zig/issues/6322): Convention, deinit doesn’t invalidate ([closed/rejected in November 2021](https://github.com/ziglang/zig/issues/6322#event-5662839267)).
  - This proposal suggested that "by convention, `deinit` never invalidates memory and always takes `self` as a value, i.e. the opposite of what I proposed/assumed above.

- Issue [#9814](https://github.com/ziglang/zig/issues/9814): Constness inconsistencies in the standard library (still open).
  - Here, inconsistencies in Zig’s standard library are brought up, specifically regarding functions that invalidate values.
  - As of January 2022, @andrewrk [states that](https://github.com/ziglang/zig/issues/9814#issuecomment-1006040818) he is “willing to walk back the current convention, which is leaning towards mutable self pointer for deinit.” (I assume this means that there was a leaning towards using `self: *Self` for deinitialization, but openness to shift towards using `self: Self` instead.)

However, if I understand right, turning down PRO happened about [two and a half years later](https://github.com/ziglang/zig/issues/5973#event-14438406910), which leaves me wondering if shifting towards `self: Self` is still a good idea.

So it looks like the question is unresolved yet. I hope any inconsistencies in `std` will get resolved, and that there will be an easy rule I can follow as a programmer when creating my own `deinit` functions.

I personally feel like “`noalias self: *Self`” is the right solution, because it allows the implementer of `deinit` to modify the value during the process of invalidation, which might come in handy (and, as a bonus, be able to set it to [`undefined`](https://ziglang.org/documentation/0.14.1/#undefined) in the end).

But I would really like to hear other people’s opinion on that, and maybe arguments/implications that I’m overlooking.

* * *

_P.S.:_ I think requiring a mutable pointer is also semantically correct because it forces the user to use `var` rather than `const`, which is (in my opinion) correct, as invalidation is some sort of mutation the programmer should be aware of.

---

_[View the full topic](https://ziggit.dev/t/which-arguments-for-deinit-or-other-invalidating-functions/10782)._
