T.init, struct destructors and invariants - should they be called?

Simen Kjærås simen.kjaras at gmail.com
Fri Jul 6 12:10:58 UTC 2018


On Friday, 6 July 2018 at 10:44:09 UTC, FeepingCreature wrote:
> 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.

The rest looks sensible to me, but I have to say this is 
bollocks. This Nullable never has to construct an S.init:

struct Nullable(T) {
     ubyte[T.sizeof] _payload;
     bool _hasValue;

     @property @trusted
     ref T value() {
         assert(_hasValue);
         return *cast(T*)_payload.ptr;
     }

     @property @trusted
     void value(T val) {
         cleanup();
         _hasValue = true;
         _payload = *cast(typeof(_payload)*)&val;
     }

     @property
     void value(typeof(null)) {
         cleanup();
         _hasValue = false;
     }

     @trusted
     private void cleanup() {
         if (!_hasValue) return;
         destroy(*cast(T*)_payload.ptr);
         _hasValue = false;
     }

     this(T val) {
         value = val;
     }

     ~this() {
         cleanup();
     }

     this(typeof(null) val) {
         value = val;
     }

     void opAssign(T val) {
         value = val;
     }

     void opAssign(typeof(null) val) {
         value = val;
     }
}

struct S
{
     Object obj;
     invariant
     {
         assert(this.obj !is null);
     }
     @disable this();
     @safe
     this(Object obj)
     {
         this.obj = obj;
     }
     @safe ~this() {}
}

@safe unittest {
     Nullable!S a; // Look ma, no assert!
}

Not only do I think it's unnecessary for Nullable to declare a T 
field, I think it's a bug if it does. The destructor problem you 
point out is one of the key reasons for this.

--
   Simen


More information about the Digitalmars-d mailing list