I believe there's a good case that struct invariants should not be called on struct destruction. Significantly, I believe that Phobos, in particular `moveEmplace`, is already written as if this is the case, even though it is not specified anywhere.

It is very common for structs' .init to violate invariants. Consider the humble struct S
{
    Object obj;
    invariant
    {
        assert(this.obj !is null);
    }
    @disable this();
    this(Object obj)
    in(obj !is null)
    {
        this.obj = obj;
    }
}

S is obviously intended to be constructed with a nonzero this.obj. However, even in @safe code we may take S.init, which violates the invariant.

Consequently, this code currently asserts out:

    S s = S.init;

Why is this a problem? ("Just don't use S.init!")

Well, for one it makes Nullable!S impossible. Nullable, if it is to be @nogc, *necessarily* has to construct an S.init struct member. This leads us into trouble:

    Nullable!s ns = Nullable!s();

^ Asserts out again - there is no way for Nullable to avoid invoking the destructor of its internal S field.

Now, currently this is not a problem because Nullable refuses to compile in this case. However, such a basic language feature should *really* work for every type, especially given that such basic types as SysTime already set up Nullable's reasonable fears of invalid behavior.

There is a simple tweak to make this work:

Simply require that struct constructors be defined for T.init, even if T.init should violate invariants. This can be implemented by not checking the invariant if `this is T.init`, or simply disabling the invariant in the struct destructor entirely.

I picked the second option, but more because I didn't know how to do the first.

https://github.com/dlang/dlang.org/pull/2410

https://github.com/dlang/dmd/pull/8462

About `moveEmplace`: If `moveEmplace` detects that the struct type it is operating on has a user-defined destructor, it manually overwrites its source with `T.init`. This suggests that `moveEmplace` already operates on this logic. Hence: it's necessary, it's unavoidable, and it has precedent.

Opine?

Reply via email to