Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
February 07, 2015 Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
I'm writing a blog post about why we don't need rvalue references in D. It seems that we rely on NRVO being performed, not just as an optimization, but for correct semantics (e.g. for objects without destructors or postblits). This doesn't appear to be documented anywhere. Is it meant to be part of the spec? Relevant issues: See: https://issues.dlang.org/show_bug.cgi?id=10372 https://issues.dlang.org/show_bug.cgi?id=12180 |
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | "Peter Alexander" wrote in message news:uiqnamficseklfowmkyf@forum.dlang.org... > I'm writing a blog post about why we don't need rvalue references in D. It seems that we rely on NRVO being performed, not just as an optimization, but for correct semantics (e.g. for objects without destructors or postblits). This doesn't appear to be documented anywhere. > > Is it meant to be part of the spec? NRVO isn't required for correct semantics, as structs can be moved with bitcopy. |
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On 2/7/15 6:35 AM, Daniel Murphy wrote:
> "Peter Alexander" wrote in message
> news:uiqnamficseklfowmkyf@forum.dlang.org...
>
>> I'm writing a blog post about why we don't need rvalue references in
>> D. It seems that we rely on NRVO being performed, not just as an
>> optimization, but for correct semantics (e.g. for objects without
>> destructors or postblits). This doesn't appear to be documented anywhere.
>>
>> Is it meant to be part of the spec?
>
> NRVO isn't required for correct semantics, as structs can be moved with
> bitcopy.
It is required for structs that disable postblit. -- Andrei
|
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On Saturday, 7 February 2015 at 14:46:55 UTC, Daniel Murphy wrote:
> NRVO isn't required for correct semantics, as structs can be moved with bitcopy.
Yes, you're right. I suppose what I mean is that it should be guaranteed that returning a local Lvalue by value should always be moved to the caller destination, rather than copied then destroyed.
S foo() {
S s;
return s;
}
S s = foo(); // no destructors or postblits should be called here
The spec needs to guarantee this, otherwise unary std.algorithm.move isn't guaranteed to work for non-copyable types.
|
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Saturday, 7 February 2015 at 15:02:43 UTC, Andrei Alexandrescu wrote:
> On 2/7/15 6:35 AM, Daniel Murphy wrote:
>> "Peter Alexander" wrote in message
>> news:uiqnamficseklfowmkyf@forum.dlang.org...
>>
>>> I'm writing a blog post about why we don't need rvalue references in
>>> D. It seems that we rely on NRVO being performed, not just as an
>>> optimization, but for correct semantics (e.g. for objects without
>>> destructors or postblits). This doesn't appear to be documented anywhere.
>>>
>>> Is it meant to be part of the spec?
>>
>> NRVO isn't required for correct semantics, as structs can be moved with
>> bitcopy.
>
> It is required for structs that disable postblit. -- Andrei
NRVO specifically means that a pointer to the destination object is passed to the function, and the returned object is constructed in place. The in place construction isn't required. What is required is that the local is moved.
e.g.
S foo() {
S s;
return s;
}
S s = foo();
With NRVO becomes:
void foo(ref S dst) {
dst = S();
}
S s = void;
foo(s);
But this isn't necessary. Would also be valid to just do:
void foo(ref S dst) {
S s;
move(dst, s); // do the memcpys
}
S s;
foo(s);
This distinction matters because NRVO cannot be performed when foo may return two different objects, but we can still move and avoid postblit.
|
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Peter Alexander | "Peter Alexander" wrote in message news:gverkczeotvadwmdowdl@forum.dlang.org... > Yes, you're right. I suppose what I mean is that it should be guaranteed that returning a local Lvalue by value should always be moved to the caller destination, rather than copied then destroyed. > > S foo() { > S s; > return s; > } > S s = foo(); // no destructors or postblits should be called here > > The spec needs to guarantee this, otherwise unary std.algorithm.move isn't guaranteed to work for non-copyable types. Yeah, the spec needs to guarantee no copies. Kenji Hara has done some work on this. |
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | "Andrei Alexandrescu" wrote in message news:mb59ej$2j7s$1@digitalmars.com... > > NRVO isn't required for correct semantics, as structs can be moved with > > bitcopy. > > It is required for structs that disable postblit. -- Andrei IIRC they only require that no copies are made. They can still be moved. |
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Murphy | On 2/7/15 8:02 AM, Daniel Murphy wrote:
> "Andrei Alexandrescu" wrote in message
> news:mb59ej$2j7s$1@digitalmars.com...
>
>> > NRVO isn't required for correct semantics, as structs can be moved with
>> > bitcopy.
>>
>> It is required for structs that disable postblit. -- Andrei
>
> IIRC they only require that no copies are made. They can still be moved.
Exactly - as you just said in the other post, the spec must clarify when things are guaranteed to be moved and not copied.
That includes:
1. URVO: returning an rvalue does not entail a copy.
2. Last return of a function local variable does not entail a copy.
That's actually more than NRVO because NRVO requires the same local be returned from all paths. Example:
T fun(bool b) {
if (b) { T a; return a; }
T b;
return b;
}
This should work if T is noncopyable. It may be less efficient than it could though.
3. The more complicated/ambitious cases involve the last use of a value. Consider:
T fun() {
T a;
T b = a;
return b;
}
Even though the code ostensibly makes a copy, it's the last use of a so that could be a move.
I think (3) could be used for optimization but it's too much of a headache to put in the language definition. We do need to have (1) and (2) covered.
Andrei
|
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Saturday, 7 February 2015 at 16:10:48 UTC, Andrei Alexandrescu wrote: > On 2/7/15 8:02 AM, Daniel Murphy wrote: >> "Andrei Alexandrescu" wrote in message >> news:mb59ej$2j7s$1@digitalmars.com... >> >>> > NRVO isn't required for correct semantics, as structs can be moved with >>> > bitcopy. >>> >>> It is required for structs that disable postblit. -- Andrei >> >> IIRC they only require that no copies are made. They can still be moved. > > Exactly - as you just said in the other post, the spec must clarify when things are guaranteed to be moved and not copied. > > That includes: > > 1. URVO: returning an rvalue does not entail a copy. > > 2. Last return of a function local variable does not entail a copy. I think this needs to be phrased differently: Any returned value can be moved iff none of the destructors, scope(exit)'s and finallys that are run as part of the cleanup can possibly access the value's original location. (I assume that the move happens _before_ the destructors are called. This is reasonable because otherwise said destructors could modify the returned value "in flight".) This formulation also encompasses rvalues. > > That's actually more than NRVO because NRVO requires the same local be returned from all paths. Example: > > T fun(bool b) { > if (b) { T a; return a; } > T b; > return b; > } > > This should work if T is noncopyable. It may be less efficient than it could though. > > 3. The more complicated/ambitious cases involve the last use of a value. Consider: > > T fun() { > T a; > T b = a; > return b; > } > > Even though the code ostensibly makes a copy, it's the last use of a so that could be a move. This is arguably different, because it doesn't involve a return. > > I think (3) could be used for optimization but it's too much of a headache to put in the language definition. We do need to have (1) and (2) covered. > > > Andrei |
February 07, 2015 Re: Is NRVO part of the spec? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | On Saturday, 7 February 2015 at 16:10:48 UTC, Andrei Alexandrescu wrote:
> On 2/7/15 8:02 AM, Daniel Murphy wrote:
>> "Andrei Alexandrescu" wrote in message
>> news:mb59ej$2j7s$1@digitalmars.com...
>>
>>> > NRVO isn't required for correct semantics, as structs can be moved with
>>> > bitcopy.
>>>
>>> It is required for structs that disable postblit. -- Andrei
>>
>> IIRC they only require that no copies are made. They can still be moved.
>
> Exactly - as you just said in the other post, the spec must clarify when things are guaranteed to be moved and not copied.
>
> That includes:
>
> 1. URVO: returning an rvalue does not entail a copy.
>
> 2. Last return of a function local variable does not entail a copy.
>
> That's actually more than NRVO because NRVO requires the same local be returned from all paths. Example:
>
> T fun(bool b) {
> if (b) { T a; return a; }
> T b;
> return b;
> }
>
> This should work if T is noncopyable. It may be less efficient than it could though.
>
> 3. The more complicated/ambitious cases involve the last use of a value. Consider:
>
> T fun() {
> T a;
> T b = a;
> return b;
> }
>
> Even though the code ostensibly makes a copy, it's the last use of a so that could be a move.
>
> I think (3) could be used for optimization but it's too much of a headache to put in the language definition. We do need to have (1) and (2) covered.
>
>
> Andrei
Perfect. Clear and reasonable.
|
Copyright © 1999-2021 by the D Language Foundation