Discussion Thread: DIP 1040--Copying, Moving, and Forwarding--Community Review Round 1

Q. Schroll qs.il.paperinik at gmail.com
Wed Mar 17 17:14:04 UTC 2021


On Thursday, 11 March 2021 at 03:33:31 UTC, Walter Bright wrote:
> On 3/10/2021 5:27 PM, tsbockman wrote:
>> On Thursday, 11 March 2021 at 00:31:01 UTC, deadalnix wrote:
>>> On Wednesday, 10 March 2021 at 22:51:58 UTC, tsbockman wrote:
>>>> Am I the only one who thinks that it would be better to have 
>>>> syntax that accurately reflects the semantics, instead of 
>>>> just documenting "this syntax is a lie"?
>>>
>>> No, I think there is a problem with using opAssign here, 
>>> because "this" will refers to something that is possibly 
>>> uninitialized, and the old value may not be consumed fully.
>>>
>>> Due to problem #1, this kinda need to be a constructor rather 
>>> than an opAssign.
>
> opAssign is only for assigning to initialized objects. 
> Constructors are for uninitialized objects.
>
>
>> Yeah, studying the DIP I can't figure out what problem the 
>> move `opAssign` is supposed to solve that the constructor 
>> doesn't:
>> https://forum.dlang.org/post/kzgybicwqwlfyiiefucc@forum.dlang.org
>
> The thing about "destroy after move" is to deal with the case 
> of both the source and the destination referring to the same 
> object. The concern is that destroying the destination's 
> original contents first will destroy them for the source before 
> it gets moved in.
>
> It's the same problem "swap" has. It's also necessary semantics 
> for a reference counted object.

It might be a stupid question, but why have move assignment in 
the first place? In C++, there's the copy-and-swap idiom[1]. 
Maybe it's obvious why it does not apply in D, but if using a 
swap function makes implementing a copy assignment and move 
assignment trivial, why not requiring opSwap instead of opAssign 
for an elaborate move object?

Basically, opSwap takes a typeof(this) lvalue (by reference), 
well, swaps contents with `this`. Usually, this means swapping 
all member variables (can be auto-generated easily). Then,

     ref typeof(this) opAssign(typeof(this) rhs)
     {
         this.opSwap(rhs);
         return this;
     }

does the deed. Note that the call to opAssign is to be treated 
like any old member function call. If the argument is an rvalue 
(or by the DIP the last use of an lvalue), the move constructor 
is used to initialize the parameter. Otherwise the copy 
constructor is used to initialize the parameter.

This is not a "let's do it like C++ guides" but rather "let's not 
repeat the mistakes C++ made". Because in C++, if one don't know 
copy-and-swap, one's copy/move assignment operator is probably 
worse than the copy-and-swap one.

Note that in C++, too, copy-and-swap only applies to elaborate 
move objects.

[1] 
https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom


More information about the Digitalmars-d mailing list