Jump to page: 1 27  
Page
Thread overview
[dmd-beta] rvalue references
Apr 11, 2012
Walter Bright
Apr 11, 2012
kenji hara
Apr 11, 2012
Jonathan M Davis
Apr 11, 2012
Walter Bright
Apr 11, 2012
Jonathan M Davis
Apr 11, 2012
Jason House
Apr 11, 2012
Walter Bright
Apr 11, 2012
Jason House
Apr 11, 2012
Michel Fortin
Apr 11, 2012
Jonathan M Davis
Apr 11, 2012
Jonathan M Davis
Apr 12, 2012
Dmitry Olshansky
Apr 12, 2012
Dmitry Olshansky
Apr 13, 2012
Dmitry Olshansky
Apr 12, 2012
Jason House
Apr 16, 2012
Sean Kelly
Apr 16, 2012
Jonathan M Davis
Apr 16, 2012
Jason House
Apr 16, 2012
Jonathan M Davis
Apr 16, 2012
Jason House
Apr 16, 2012
Michel Fortin
[dmd-beta] ref semantics
Apr 12, 2012
Michel Fortin
Apr 12, 2012
Max Samukha
Apr 12, 2012
Andrej Mitrovic
Apr 12, 2012
Jonathan M Davis
Apr 12, 2012
Andrej Mitrovic
Apr 12, 2012
Jonathan M Davis
Apr 12, 2012
Andrej Mitrovic
Apr 12, 2012
Michel Fortin
Apr 12, 2012
Andrej Mitrovic
Apr 13, 2012
Jonathan M Davis
Apr 13, 2012
Andrej Mitrovic
Apr 13, 2012
Jonathan M Davis
Apr 13, 2012
Don Clugston
Apr 13, 2012
Jonathan M Davis
Apr 15, 2012
Sean Kelly
Apr 16, 2012
Jonathan M Davis
Apr 16, 2012
Sean Kelly
Apr 13, 2012
kenji hara
Apr 13, 2012
kenji hara
Apr 13, 2012
kenji hara
Apr 11, 2012
Jonathan M Davis
Apr 11, 2012
Walter Bright
Apr 11, 2012
Jonathan M Davis
Apr 11, 2012
Jacob Carlborg
Apr 12, 2012
Sean Kelly
Apr 12, 2012
Masahiro Nakagawa
April 10, 2012
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
2012$BG/(B4$B7n(B11$BF|(B9: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
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

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
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
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

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
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
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
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 6 7