View mode: basic / threaded / horizontal-split · Log in · Help
April 10, 2012
[dmd-beta] rvalue references
I couldn't remember what the big problem was with rvalue references, and so I 
spent some time on the phone talking with Andrei about what exactly the problem 
is. They are:

1.
C++:
  int i;
  double& d = i;
  ++d;

The problem is that i is implicitly converted to a double, and then the address 
is taken and assigned to d. When what d refers to is incremented, it increments 
the temporary, and i is inexplicably left untouched. I say inexplicably because 
when an implicit conversion happens isn't always obvious to the user. C++ is 
full of implicit conversions, so these types of silent bugs crop up.

This one isn't too bad, you could say "just make it a const&", but consider the 
related:

2.
  double& d;
  int i;
  void foo() {
    d = i;
  }

Now d is referring to a temporary that has gone out of scope. This is, of 
course, a memory corrupting disaster, const ref or no const.

3. This one is a more general problem with references, that of escaping 
references to locals:
  double& d;
  void foo(double x, double y) {
     d = x + y;
  }

OMG LOL big oops, we've now got a reference to a temporary that goes out of scope.

---------------------------------------------
Our D solution, disallowing rvalue references, is technically sound but as we've 
discussed here is a usability disaster, and auto ref isn't going to cut it. We 
figured a solution is:

*** Allow rvalue references, however, disallow any implicit conversions of the 
literal's type in the process of taking a reference to it. ***

That takes care of 1 and 2. The solution to 3 is a bit more subtle. Some people 
have wondered why the D compiler can create reference types itself, but does not 
allow the user to outside of function parameters and foreach variables. This is 
the reason why. References, in order to be safe, must not be allowed to escape a 
scope. They can only be passed downward to enclosed scopes, and returned from 
functions where the return value is checked. Also, one cannot take the address 
of a reference. I think this closes the holes.

With all that, I intend to once again allow struct literals to be lvalues for 
2.059. Somewhat later, also allow references to other literals like 0 and 5.6.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 11, 2012
Re: [dmd-beta] rvalue references
2012年4月11日9:57 Walter Bright <walter@digitalmars.com>:
> *** Allow rvalue references, however, disallow any implicit conversions of
> the literal's type in the process of taking a reference to it. ***

It sounds good. After the changing, following code may work.

struct S {
   int val;
   bool opEquals(const ref S rhs) const { return val == rhs.val; }
}
void main() {
 S s1 = S(10);
 assert(S == S(10));
   // S(10) is rvalue but you can bind it with ref as *rvalue reference*.
}

> With all that, I intend to once again allow struct literals to be lvalues for 2.059.

But it sounds not good. We should keep all kind of literals (includinc
struct ones) as rvalue.

struct S {}
void f(    S s) { printf("receives rvalue\n"); }
void f(ref S s) { printf("receives lvalue\n"); }
viod main() {
 f(S());
   // if you revert struct literal to lvalue, this call matches both
ovarloads of f,
   // then causes ambiguous error.
}

> Somewhat later, also allow references to other literals like 0 and 5.6.

Agreed. Introducing *rvalue reference* requires such changes for consistency.
But, again, keep all literals rvalue, please.

Kenji Hara
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On Wednesday, April 11, 2012 10:23:44 kenji hara wrote:
> Agreed. Introducing *rvalue reference* requires such changes for
> consistency. But, again, keep all literals rvalue, please.

Indeed. It's incredibly inconsistent for struct literals to be lvalues. 
Literals should always be rvalues. Allowing references to them with something 
like const& like in C++ is of value, but that's of value with _all_ 
temporaries. struct literals should not be treated specially from other 
literals or temporaries. Having

void func(ref S s) {}
S foo() {}
func(S(1)); //succeeds
func(foo()); //fails

is atrocious. It's incredibly inconsistent and confusing. S(1) should treated 
identically as the return value of foo().

If we need to continue to allow struct literals to be lvalues just for this 
release in order to restrict code breakage while we sort out how we're going 
to deal with const ref and rvalues, then that's fine, as undesirable as it may 
be, but struct literals should _not_ be lvalues in the long run.

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On 4/10/2012 8:11 PM, Jonathan M Davis wrote:
> On Wednesday, April 11, 2012 10:23:44 kenji hara wrote:
>> Agreed. Introducing *rvalue reference* requires such changes for
>> consistency. But, again, keep all literals rvalue, please.
> Indeed. It's incredibly inconsistent for struct literals to be lvalues.
> Literals should always be rvalues. Allowing references to them with something
> like const&  like in C++ is of value, but that's of value with _all_
> temporaries. struct literals should not be treated specially from other
> literals or temporaries. Having
>
> void func(ref S s) {}
> S foo() {}
> func(S(1)); //succeeds
> func(foo()); //fails
>
> is atrocious. It's incredibly inconsistent and confusing. S(1) should treated
> identically as the return value of foo().

These will both work under my proposal.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On Tuesday, April 10, 2012 20:29:40 Walter Bright wrote:
> On 4/10/2012 8:11 PM, Jonathan M Davis wrote:
> > On Wednesday, April 11, 2012 10:23:44 kenji hara wrote:
> >> Agreed. Introducing *rvalue reference* requires such changes for
> >> consistency. But, again, keep all literals rvalue, please.
> > 
> > Indeed. It's incredibly inconsistent for struct literals to be lvalues.
> > Literals should always be rvalues. Allowing references to them with
> > something like const&  like in C++ is of value, but that's of value with
> > _all_ temporaries. struct literals should not be treated specially from
> > other literals or temporaries. Having
> > 
> > void func(ref S s) {}
> > S foo() {}
> > func(S(1)); //succeeds
> > func(foo()); //fails
> > 
> > is atrocious. It's incredibly inconsistent and confusing. S(1) should
> > treated identically as the return value of foo().
> 
> These will both work under my proposal.

With plain ref? const ref is one thing, but I'd be very nervous about letting 
ref take a temporary.

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On Apr 10, 2012, at 8:57 PM, Walter Bright <walter@digitalmars.com> wrote:

> Our D solution, disallowing rvalue references, is technically sound but as we've discussed here is a usability disaster, and auto ref isn't going to cut it. We figured a solution is:
> 
> *** Allow rvalue references, however, disallow any implicit conversions of the literal's type in the process of taking a reference to it. ***
> 
> That takes care of 1 and 2. The solution to 3 is a bit more subtle. Some people have wondered why the D compiler can create reference types itself, but does not allow the user to outside of function parameters and foreach variables. This is the reason why. References, in order to be safe, must not be allowed to escape a scope. They can only be passed downward to enclosed scopes, and returned from functions where the return value is checked. Also, one cannot take the address of a reference. I think this closes the holes.
> 
> With all that, I intend to once again allow struct literals to be lvalues for 2.059. Somewhat later, also allow references to other literals like 0 and 5.6.

Sounds like a good change.

Just to be clear, ultimately all literals will be rvalues? Can rvalues be passed as const ref but not ref? I would assume the answer to both would be 'yes'.

While I have no plans to use it, what mechanism, if any, will allow escaping the address? Usually, casts are the back door, but I don't believe that works in this case.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On 4/10/2012 8:36 PM, Jason House wrote:
> Just to be clear, ultimately all literals will be rvalues? Can rvalues be passed as const ref but not ref?

1. Yes, 2. probably no.

>
> While I have no plans to use it, what mechanism, if any, will allow escaping the address? Usually, casts are the back door, but I don't believe that works in this case.

Case 3.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On 4/10/12 7:57 PM, Walter Bright wrote:
> 2.
> double& d;
> int i;
> void foo() {
> d = i;
> }

This example is off; a reference can't be rebound. The relevant example is:

void increment(double& d)
{
    ++d;
}
...
int i;
increment(i);

People think the int has been incremented, but in fact a useless 
temporary has.

The discussion about what to do in D has been a bit longer and more 
far-reaching than Walter mentioned.

The long-term plan is to never let the address of a ref escape the 
expression in which the ref occurs. That means in essence that user code 
can't take the address of a ref.

Once that is in place, we will know for sure that all ref passed into 
and returned by functions will not escape the immediate expression in 
which that happens - great for safe code.

People who need to take &this and escape it (e.g in linked lists 
implemented with struct) will not be able to; they'll have to use static 
functions and pointers for that. Generally any work that involves 
escaping pointers will have to use pointers, not references.

I think this puts us in a very good spot:

1. Safe code will be able to use ref liberally

2. Functions will be able to return ref knowing the ref won't survive 
the current expression. This is awesome for sealed containers - safe and 
fast.

What does this have to do with rvalues and lvalues? It means that with 
the appropriate precautions, we _can_ transform rvalues into lvalues, 
because we know their address can't unsafely escape.

There is one precautions to take: we should never convert a value of 
type T to a ref of another type U. That would cause the problems we 
learned from C++. There are 3 cases of such implicit conversions:

1. built-in numerics, e.g. an int should not convert to a ref double.

2. Class inheritance, e.g. a Widget should not convert to a ref Object.

3. alias this, e.g.:

struct T {}
struct A { @property T fun(); alias fun this; }
void fun(ref T);
...
A a;
fun(a); // should not work


I think this all holds water. Destroy!

Andrei

_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On Tuesday, April 10, 2012 23:33:11 Andrei Alexandrescu wrote:
> I think this all holds water. Destroy!

So, this essentially erases the difference between lvalues and rvalues as far 
as ref is concerned? ref will effectively have nothing to do with lvalues or 
rvalues?

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
April 10, 2012
Re: [dmd-beta] rvalue references
On Tuesday, April 10, 2012 17:57:01 Walter Bright wrote:
> *** Allow rvalue references, however, disallow any implicit conversions of
> the literal's type in the process of taking a reference to it. ***

Are you intending to implement this for 2.059 or wait for 2.060? It would 
certainly mitigate the issues that we've been having with opEquals and opCmp, 
but it would obviously delay the release a bit.

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta
« First   ‹ Prev
1 2 3 4 5
Top | Discussion index | About this forum | D home