Move semantics for D

monarch_dodra monarch_dodra at gmail.com
Fri Jul 13 01:06:07 PDT 2012


On Friday, 13 July 2012 at 06:50:02 UTC, Benjamin Thaut wrote:
> Move semantics in C++0x are quite nice for optimization 
> purposes. Thinking about it, it should be fairly easy to 
> implement move semantics in D as structs don't have identity. 
> Therefor a move constructor would not be required. You can 
> already move value types for example within an array just by 
> plain moving the data of the value around. With a little new 
> keyword 'mov' or 'move' it would also be possible to move value 
> types into and out of functions, something like this:
>
> mov Range findNext(mov Range r)
> {
>   //do stuff here
> }
>
> With something like this it would not be neccessary to copy the 
> range twice during the call of this function, the compiler 
> could just plain copy the data and reinitialize the origin in 
> case of the argument.
> In case of the return value to only copying would be neccessary 
> as the data goes out of scope anyway.
>
> The only question would be if this causes any problems with out 
> contracts.
>
> The pre C++0x move trick, reserving a bit in the value 
> representation for marking that the next copy is a move, is 
> unfortunately not possible D because D does not have a copy 
> constructor.
>
> I for example have a range that iterates over a octree and thus 
> needs to internally track which nodes it already visited and 
> which ones are still left. This is done with a stack container. 
> That needs to be copied everytime the range is copied, which 
> causes quite some overhead.
>
> Kind Regards
> Benjamin Thaut

I'm pretty sure D already has it: Values types are "moved" in and 
out of function, implicitly, when possible, without any special 
semantics.

For "return by value", the value is simply "blit copied" 
(memcopy), when returning a local variable. Neither the source 
constructor is called, nor the target postblit constructor. Just 
binary bit copy.

For passing in by value, the compiler will do the same trick "if 
and when" it can detect you are never going to use said value 
again. If you are, you can always force a move using an explicit 
std.algorithm.move:
"myRange = findNext(move(myRange));"

You get pretty the same effect as in C++11, except:
a) the compiler will eagerly move stuff for you
b) you don't even have to define fun(T&&) (Whew)

Finally, if you want to remove the responsibility of the move 
from the caller to the callee, I *guess* you can always just pass 
by ref and do stuff there:

Range findNext(ref Range r)
{
    auto r2;
    move(r, r2); //move r into r2
    //do stuff here
    return r2; //move return
}

Note that while it might seem useless to move r into r2 (since 
you already have r by reference), you still have to move into a 
local temporary so that the compiler can "move" r2 out of 
findNext. The above function will make 0 calls to this(this) and 
0 calls to ~this. There will be about two copies of this.init.

...of course, at this point, one could wonder why:
a) you don't just take a ref, and return void?
b) Use the safer just as efficient "myRange = 
findNext(move(myRange));"


More information about the Digitalmars-d mailing list