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

Stanislav Blinov stanislav.blinov at gmail.com
Mon Nov 19 01:46:34 UTC 2018


On Sunday, 18 November 2018 at 19:33:44 UTC, FeepingCreature 
wrote:
> On Sunday, 18 November 2018 at 15:45:51 UTC, Stanislav Blinov 
> wrote:

>> Anyway, my point is that unions *are* the tool for that 
>> particular job, just like you said initially. Which has little 
>> to do with the actual topic :)
>> For example, I'd argue that the *actual* implementation *must* 
>> `move` it's passed-by-value argument (regardless of what it 
>> uses for storage), because the caller already made a required 
>> copy. But that means wiping out the argument back to T.init, 
>> and then we're back to square one.
>
> Right, which is why we make a *second* copy, store it in a 
> Union, and moveEmplace that.

You misunderstood what I said, and as you saw in my last example 
you don't need a moveEmplace for the current implementation. What 
I'm saying is, the actual implementation *should* be doing this:

void opAssign(T rhs) {
     // ...
     move(rhs, myOwnStorage);
     // ...
}

T, for all I know, could be non-copyable, i.e. a Unique. That way 
the onus of making an instance falls solely on the caller, while 
Nullalbe would never call or deal with any copy constructors. 
Recall that D "frowns upon" self-referencing types. Although the 
language can't statically disallow them, it's free to assume they 
don't exist. Therefore, moving values around without calling 
their copy ctors should be acceptable.
That's not a `union` problem. If you do it like this where T is 
your S, you'll get an assert due to invariant. I.e. that is the 
subject problem :)

> ...But to me, that indicates that @safe is broken, and I really 
> don't believe in breaking an unrelated feature in order that I 
> can coincidentally unbreak the original brokenness manually. 
> And no, just because I put a fancy term on the brokenness 
> doesn't make it any less broken. Unions let me take a @safe 
> expression whose copy constructor has ran and avoid calling its 
> destructor. This is useful because @safe would otherwise 
> require me to run a destructor on some expressions whose 
> constructor has never run. But two wrong designs don't make a 
> correct design. Just because the building is on fire doesn't 
> validate the decision to leave a giant jagged hole in the front 
> wall.

Again, that is not a `union` problem, that's a 
destructor+invariant problem. Types in .init state should be 
destructible, period:

S[] a;
// can't do this:
a = new S[10];
// but still can do this:
a.length = 10;


More information about the Digitalmars-d mailing list