www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Rvalue references

reply Jiyan <jiyan jiyan.info> writes:
Sry i know i asked it already in IRC:
Are rvalue references already solved with auto ref?

https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-and-then-not-using-it

Says rvalues are moved!

The other solution seems not so practical.

Is any solution to them intended, or was all the talk about 
rvalue references simply discarded?

Thanks :)
Jan 08
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, January 08, 2018 23:07:52 Jiyan via Digitalmars-d-learn wrote:
 Sry i know i asked it already in IRC:
 Are rvalue references already solved with auto ref?

 https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-re
 f-and-then-not-using-it

 Says rvalues are moved!

 The other solution seems not so practical.
rvalue references do not exist in D. auto ref makes it so that the refness of a parameter or return type of a templated function depends on whether its' an lvalue or rvalue. e.g. auto foo(T)(auto ref T t) { return t; } foo(42); will result in foo being instantiated as int foo(int t) { return t; } whereas int i; foo(i); will result in foo being instantiated as int foo(ref int t) { return t; } So, by using auto ref, a function can accept both lvalues and rvalues. And in D, rvalues get moved, not copied. https://stackoverflow.com/questions/35120474/does-d-have-a-move-constructor https://stackoverflow.com/questions/6884996/questions-about-postblit-and-move-semantics
 Is any solution to them intended, or was all the talk about
 rvalue references simply discarded?
Andrei has said on a number of occasions that he does not want rvalue references in D, and as I understand it, he considers them to have been a mistake in C++. There has been occasional talk of defining a way to have ref (or something similar to ref) accept rvalues in addition to lvalues, but it would have to be done in a way that would satisfy Andrei and his concern about rvalue references. I don't know what that would look like, and thus far, no one has create a DIP for such a feature. I think that the solution that most folks have gone with is simply passing everything by value unless it needs to be passed by ref so that the argument can be mutated. And then if profiling indicates that that's a performance problem in a particular case, then auto ref gets used, or the function gets overloaded on refness, or the code is refactored in some other way such that it's not passing around an object that is expensive to copy, or the object is turned into a reference type. The fact that D moves rvalues tends to mean that the only cases where expensive copying would be a problem are with large objects passed as lvalues or with objects with expensive postblits which are passed by value (and expensive postblits are generally discouraged). But the most efficient thing to do there depends on the code and how it interacts with the optimizer such that assuming what's going to be more efficient can often be wrong (especially if the object is smaller). In most cases, worrying about excessive copying seems to tend to be a premature optimization, though if an object is particularly large, then odds are it should probably be a reference type. Either way, in most cases, I'd suggest not worrying all that much about the cost of copying objects unless you have evidence that it's actually a problem with your code, and when it is, that usually means that using a reference type would be better, but auto ref is there for those cases where it makes sense to templatize a function on refness to pass objects more efficiently (or simply for when refness needs to be passed on for one reason or another). - Jonathan M Davis
Jan 08
parent reply Tony <tonytdominguez aol.com> writes:
On Monday, 8 January 2018 at 23:31:27 UTC, Jonathan M Davis wrote:

 auto foo(T)(auto ref T t)
 {
     return t;
 }

 foo(42);

 will result in foo being instantiated as

 int foo(int t)
 {
     return t;
 }

 whereas

 int i;
 foo(i);

 will result in foo being instantiated as

 int foo(ref int t)
 {
     return t;
 }

 So, by using auto ref, a function can accept both lvalues and 
 rvalues. And in D, rvalues get moved, not copied.
What does it mean to "move" a variable/value instead of copying it? Was "auto ref" created for anything besides structs?
Jan 11
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, January 12, 2018 01:59:49 Tony via Digitalmars-d-learn wrote:
 On Monday, 8 January 2018 at 23:31:27 UTC, Jonathan M Davis wrote:
 auto foo(T)(auto ref T t)
 {

     return t;

 }

 foo(42);

 will result in foo being instantiated as

 int foo(int t)
 {

     return t;

 }

 whereas

 int i;
 foo(i);

 will result in foo being instantiated as

 int foo(ref int t)
 {

     return t;

 }

 So, by using auto ref, a function can accept both lvalues and
 rvalues. And in D, rvalues get moved, not copied.
What does it mean to "move" a variable/value instead of copying it?
It the simplest case, it means that the compiler does a bitwise copy rather than a deep copy, but in other cases, it means that the compiler is able to use the object in-place rather than creating a deep copy that it places elsewhere. If you want to know more on the topic, you can always look into C++ move constructors. They were added so that C++ could avoid a lot of unnecessary copies. D took the approach of requiring that structs be moveable (e.g. it's undefined behavior to have a struct contain a pointer to itself), which simplifies things considerably. You can also check out the stackoverflow questions that I linked to before: https://stackoverflow.com/questions/35120474/does-d-have-a-move-constructor https://stackoverflow.com/questions/6884996/questions-about-postblit-and-move-semantics They don't anwser what a move is, but they do give more context.
 Was "auto ref" created for anything besides structs?
auto ref works with any type whatsoever, but as far as efficiency goes, it's kind of pointless for other types, because most everything else is at most 64 bits, which would be the size of a pointer on a 64-bit system. reals are larger, and if we ever get cent and ucent, those would be larger, but most stuff that isn't structs fits in 64 bits, meaning that copying them is not expensive. However, if you need to forward the refness of an argument, then auto ref can still be critical - e.g. std.conv.emplace constructs an object in memory, and if it couldn't pass the refness of the arguments on to the constructor that it calls, then constructors with ref parameters wouldn't work properly. Similarly, in templated code, you can have stuff like front on a range which may or may not return by ref, so by using auto ref on the return type of front when wrapping one range with another, the refness of the underlying range's front can be passed along. Arguably, this aspect of auto ref matters _way_ more than trying to make it more efficient to copy structs. - Jonathan M Davis
Jan 13
parent Tony <tonytdominguez aol.com> writes:
On Sunday, 14 January 2018 at 00:55:27 UTC, Jonathan M Davis 
wrote:

 [...]
It the simplest case, it means that the compiler does a bitwise copy rather than a deep copy, but in other cases, it means that the compiler is able to use the object in-place rather than creating a deep copy that it places elsewhere. If you want to know more on the topic, you can always look into C++ move constructors. They were added so that C++ could avoid a lot of unnecessary copies. D took the approach of requiring that structs be moveable (e.g. it's undefined behavior to have a struct contain a pointer to itself), which simplifies things considerably. [...]
Thanks!
Jan 13
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/8/18 6:07 PM, Jiyan wrote:
 
 Sry i know i asked it already in IRC:
 Are rvalue references already solved with auto ref?
 
 https://p0nce.github.io/d-idioms/#Rvalue-references:-Understanding-auto-ref-a
d-then-not-using-it 
 
 
 Says rvalues are moved!
But an rvalue move is cheaper. You construct it right on the stack where it needs to be, and no actual copy is happening. Then inside the function, no further indirections are needed, just stack offsets.
 The other solution seems not so practical.
The other solution exploits a hole in the "rvalues cannot be references" mantra. Because all member functions take 'this' by reference, the function call can be used to blur the line between rvalues and lvalues. It makes for some... interesting things: struct Int { int value; Int opBinary(string op : "+")(ref const Int other) const { return Int(other.value + value); } } auto v = Int(5); auto v2 = s + Int(5); // error auto v3 = Int(5) + s; // OK!
 Is any solution to them intended, or was all the talk about rvalue 
 references simply discarded?
auto ref was actually proposed as a non-template solution, but Walter implemented it the way it is now. The original proposal would have meant that rvalue references like C++ were possible (without conflating it with const). But current auto ref is what we have, so I would recommend using it. -Steve
Jan 09
parent reply Dgame <r.schuett.1987 gmail.com> writes:
On Wednesday, 10 January 2018 at 01:56:02 UTC, Steven 
Schveighoffer wrote:
 But current auto ref is what we have, so I would recommend 
 using it.
I would recommend to ignore auto ref for rvalue references. It generates 2^N functions where N is the amount of auto ref parameters. That the most awful template bloat I've ever seen.
Jan 10
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/10/18 3:08 AM, Dgame wrote:
 On Wednesday, 10 January 2018 at 01:56:02 UTC, Steven Schveighoffer wrote:
 But current auto ref is what we have, so I would recommend using it.
I would recommend to ignore auto ref for rvalue references. It generates 2^N functions where N is the amount of auto ref parameters. That the most awful template bloat I've ever seen.
It only generates 2^N functions if you call it 2^N different ways. Most of the time you call it the same way. -Steve
Jan 10
parent reply Dgame <r.schuett.1987 gmail.com> writes:
On Wednesday, 10 January 2018 at 14:41:21 UTC, Steven 
Schveighoffer wrote:
 On 1/10/18 3:08 AM, Dgame wrote:
 On Wednesday, 10 January 2018 at 01:56:02 UTC, Steven 
 Schveighoffer wrote:
 But current auto ref is what we have, so I would recommend 
 using it.
I would recommend to ignore auto ref for rvalue references. It generates 2^N functions where N is the amount of auto ref parameters. That the most awful template bloat I've ever seen.
It only generates 2^N functions if you call it 2^N different ways. Most of the time you call it the same way. -Steve
If that would be true we wouldn't need auto ref at all.
Jan 10
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/10/18 12:59 PM, Dgame wrote:
 On Wednesday, 10 January 2018 at 14:41:21 UTC, Steven Schveighoffer wrote:
 On 1/10/18 3:08 AM, Dgame wrote:
 On Wednesday, 10 January 2018 at 01:56:02 UTC, Steven Schveighoffer 
 wrote:
 But current auto ref is what we have, so I would recommend using it.
I would recommend to ignore auto ref for rvalue references. It generates 2^N functions where N is the amount of auto ref parameters. That the most awful template bloat I've ever seen.
It only generates 2^N functions if you call it 2^N different ways. Most of the time you call it the same way.
If that would be true we wouldn't need auto ref at all.
The author of the function may not be the one calling it, so he doesn't know the way you like to call it. All I'm saying is to think about that your 2^N prediction requires 2^N lines of code, all calling it different ways. It's not likely to happen. -Steve
Jan 10