Discussion: Rvalue refs and a Move construtor for D

Exil Exil at gmall.com
Wed Sep 4 21:09:27 UTC 2019


On Wednesday, 4 September 2019 at 09:20:05 UTC, kinke wrote:
> On Wednesday, 4 September 2019 at 00:33:06 UTC, Exil wrote:
>> How would it work with multi-function passing though? With a 
>> rvalue reference, you are effectively just passing around a 
>> reference, until the contents of the value are moved. So you 
>> can pass it through N functions and it won't ever to do a 
>> move/copy.
>>
>> Would you effectively be relying on the compiler to optimize 
>> out the un-necessary moves, or would they be unavoidable, as 
>> they effectively are now?
>
> Yes, by changing the ABI details to the C++ way in this regard, 
> making move/forward intrinsics and detecting them in argument 
> expressions. Laid out earlier in this thread in 
> https://forum.dlang.org/post/jogsaeqxouxaeflmgzcc@forum.dlang.org. We don't need rvalue refs in the language for that at all, just use a value parameter - rvalue args will be passed by ref under the hood, just like explicitly moved lvalue args.

So you change the ABI to pass by a pointer to the object on the 
stack. In cases where we use some "move" intrinsic, a pointer to 
a lvalue (passed in to the move()) is passed in place of the 
pointer to the object on the stack?

If I understand this correctly then this can happen:


     struct Foo
     {
         int value;
     }

     void bar(Foo foo) // for rvalues, actually: `@rvalue ref Foo 
foo`
     {
         // how do we know we are just changing the value of a 
temporary
         // that won't exist past this scope?
         foo.value = 10;
     }


     void main()
     {
         Foo lvalue;

         lvalue.value = 0;
         bar(move(lvalue)); // intrinsic move

         assert(lvalue.value == 10); // passes
     }


Because of this, even though the function doesn't use a 
reference. It could unknowingly change state outside of the scope 
of the function. That'll entirely depend on the use if they 
mistakenly use `move()` where they didn't mean to.

This would mean basically any current use of rvalue parameters 
would need to be changed to be "const". And any function that 
actually does need a copy would have to do so manually. They 
don't know what is being passed to them, so it could very well be 
making a copy twice.

     void test(Foo foo)
     {
         Foo actualFoo = foo; // make copy just in case parameter 
was `move`d in

         actualFoo.value = 10;
     }

     Foo lvalue;

     lvalue.value = 0;
     test(lvalue);              // makes 2 copies
     assert(lvalue.value == 0); // ok

     test(move(lvalue));        // makes 1 copy
     assert(lvalue.value == 0); // ok













More information about the Digitalmars-d mailing list