opAssign(int) necessitates this(this) for automatic opAssign to work

Ali Çehreli acehreli at yahoo.com
Sun Dec 27 09:40:49 PST 2009


Simen kjaeraas wrote:
 > On Sun, 27 Dec 2009 02:23:47 +0100, Ali Çehreli <acehreli at yahoo.com> 
wrote:
 >
 >> Simen kjaeraas wrote:
 >>  > On Sun, 27 Dec 2009 01:42:07 +0100, Ali Çehreli
 >> <acehreli at yahoo.com> wrote:
 >>  >
 >>  >> I've tested the following with dmd 2.037.
 >>  >>
 >>  >> The compiler generated opAssign is disabled by the definition of
 >>  >> opAssign(int). The compiler rejects the following assignment
 >>  >> operation. (The error message is in the comment below.)
 >>  >>
 >>  >> Is this by design?
 >>  >>
 >>  >> When I also define post-blit, the compiler generated opAssign is
 >>  >> available again and seems to work correctly. (My struct doesn't have
 >>  >> any members for brevity.)
 >>  >>
 >>  >> The program below compiles when this(this) is provided.
 >>  >>
 >>  >> void main()
 >>  >> {
 >>  >>      S s0;
 >>  >>      s0 = s0;    // ERROR
 >>  >> }
 >>  >
 >>  > This piece of code does post-blit, not opAssign(int).
 >>
 >> post-blit is when an object is constructed from another one. The above
 >> has two already constructed objects on both sides. So I think it is
 >> assignment.
 >>
 >>  > Try defining opAssign(S). That should work here.
 >>
 >> I know; but the problem is, defining opAssign(int) disables the
 >> compiler-generated opAssign(S); which is then interestingly available
 >> again, once this(this) is defined.
 >>
 >> I just wanted to know whether there is a compiler bug in this behavior.
 >>
 >> Ali
 >
 > Structs being what they are (Plain Old Data),

Doesn't allowing user defined post-blit and opAssign makes them not so 
anymore?

I think I read here some time ago that even copying is not blitting 
anymore, but a memberwhise copy. It would have to be, to support members 
of types that define their own this(this) anyway.

 > opAssign(typeof(this)) is
 > basically the same as this(this). In both cases, you create a copy of an
 > existing struct, and thus need to .dup referenced data that should be
 > unique, and whatever else your copying function needs.

Isn't assignment two operations together: destroying the old object and 
constructing a new one?

That brings the exception safety issue. We cannot destroy the old value 
before ensuring that the new value will be constructed successfully.

Hence, the automatic opAssign is documented to be:

S* opAssign(S s)
{   ... bitcopy *this into tmp ...
     ... bitcopy s into *this ...
     ... call destructor on tmp ...
     return this;
}

That is from http://digitalmars.com/d/2.0/struct.html

But I suspected that that defition is not exception safe; *IF copying is 
not blitting anymore. If an exception is thrown during copying s into 
*this, then we would have a half constructed object.

It was then, when I was trying to see whether the automatic assignment 
is exception-safe, that I discovered the behavior that I asked about.

 > If you define an opAssign, you've basically informed the compiler that
 > this struct should only be assignable from whatever parameters opAssign
 > takes.

Fine.

 > If you define postblit, you've said 'this struct can be
 > constructed from another instance of the same struct', meaning it's
 > assignable to itself.

I fail to see that post-blit and assignment are the same. And the 
documentation supports my understanding.

Thank you very much for your help, but because you didn't explicitly say 
that the documentation is wrong; I continue having my doubts. :)

 > If you can't, then when would you ever do a
 > postblit?

The operations post blit... ;)

Ali



More information about the Digitalmars-d mailing list