April 11, 2012
Answers within.

On 4/11/12 6:53 AM, Steve Schveighoffer wrote:
> --------------------------
> Issue 1:
>
> In TDPL, you say:
>
> for context:
> void bump(ref int x) {++x;}
>
> "If a function expects a ref, it accepts only "real" data, not
> temporaries; anything that's not an lvalue is rejected during
> compilation; for example:
>
> bump(5); // Error! Cannot bind an rvalue to a ref parameter
>
> This prevents silly mistakes when people believe work is being done but
> in fact the call has no visible affect."
>
> This is in section 5.2.1
>
> Now, this obviously becomes valid code. Are you OK with this? It seemed
> like a major explanation as to why refs don't bind to rvalues. I
> personally think it's just "coder beware".
>
> -----------------------------

The example in the book rehashes the old example by Bjarne Stroustrup in his TC++PL book. The danger is there but in a slightly different form. Consider:

short x;
bump(x);

*This* is the wrong/dangerous code because it silently increments a temporary generated from x, whereas the user may think it increments x. On the other hand, the code

bump(5);

is less dangerous because the user is unlikely to believe they incremented the literal 5 such that writing 5 again will actually mean 6! (Crazy as it sounds, something like that happens in Smalltalk. Ew.)

So converting rvalues to references is fine AS LONG AS the rvalues don't originate from lvalues of a different type.

> Issue 2:
>
> Another reason I remember you stating as to why rvalues cannot bind to
> ref is that it's not the most efficient semantics. So if rvalues bind to
> both non-ref and ref, can you have overloads between ref and non-ref for
> optimization purposes?
>
> Note that this is *valid* code with 2.058 (and probably many previous
> compilers):
>
> import std.stdio;
>
> void foo(ref int x) { writeln("ref"); }
> void foo(int x) { writeln("nonref"); }
>
> void main()
> {
> int x;
> foo(x);
> foo(5);
> }
>
> prints:
> ref
> nonref
>
> Will this still compile under the new rules, or will it be ambiguous?
>
> -----------------------------

This code should continue to compile under the new rules. A library writer should be able to distinguish rvalues from lvalues.

> Issue 3:
>
> The point that you cannot take an address of a ref value is going to
> cause a *lot* of existing code to fail. I don't really like this rule
> for code that isn't marked @safe (which should disallow taking addresses
> anyway). It seems overly restrictive, and it will be viral in nature. I
> know you mentioned this is the "long term plan", are the other parts of
> this severable from this? Is the plan to implement this right now or
> later? Can you explain why the existing requirements that you don't use
> pointers in @safe code isn't enough?
>
> -Steve
>
>
> _______________________________________________

It is true that the new rule will break code. Walter and I assess that the amount of breakage will be, however, small. Even in today's C++ it is poor style to take the address of reference variables and sneak the resulting pointer. Though sometimes this is necessary in C++, we think it already is much less so in D.

Walter likes the idea that we first introduce the restriction in @safe code alone. I think we must eventually introduce it for all code, and my understanding is that Walter is also convinced of that.


Andrei
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 11, 2012
On Apr 10, 2012, at 5:57 PM, Walter Bright wrote:

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

I'm shocked that this is legal.  Why allow implicit conversions when assigning to a reference?

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

In C++, the temporary would persist if the reference were const, correct?  How is this implemented, anyway?

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

Seems entirely reasonable.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 12, 2012
On Thu, Apr 12, 2012 at 1:06 PM, Sean Kelly <sean@invisibleduck.org> wrote:

> On Apr 10, 2012, at 5:57 PM, Walter Bright wrote:
>
> > 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;
>
> I'm shocked that this is legal.  Why allow implicit conversions when assigning to a reference?
>
>
No. In C++, this is ill-formed but MSVC accepts this code...


April 12, 2012
>
>
> Walter likes the idea that we first introduce the restriction in @safe code alone. I think we must eventually introduce it for all code, and my understanding is that Walter is also convinced of that.
>
>
>
> Andrei
> ______________________________**_________________
> dmd-beta mailing list
> dmd-beta@puremagic.com
> http://lists.puremagic.com/**mailman/listinfo/dmd-beta<http://lists.puremagic.com/mailman/listinfo/dmd-beta>
>

I think the language should allow taking addresses of references in unsafe context. One valid and fairly frequent case is passing the address to C:

extern(C) external_foo(S* s);

void foo(ref S s)
{
     external_foo(&s);
}


April 12, 2012
More responses within ;)




>________________________________
> From: Andrei Alexandrescu <andrei@erdani.com>
>
>
Answers within.
>
>On 4/11/12 6:53 AM, Steve Schveighoffer wrote:
>> --------------------------
>> Issue 1:
>>
>> In TDPL, you say:
>>
>> for context:
>> void bump(ref int x) {++x;}
>>
>> "If a function expects a ref, it accepts only "real" data, not temporaries; anything that's not an lvalue is rejected during compilation; for example:
>>
>> bump(5); // Error! Cannot bind an rvalue to a ref parameter
>>
>> This prevents silly mistakes when people believe work is being done but in fact the call has no visible affect."
>>
>> This is in section 5.2.1
>>
>> Now, this obviously becomes valid code. Are you OK with this? It seemed like a major explanation as to why refs don't bind to rvalues. I personally think it's just "coder beware".
>>
>> -----------------------------
>
>The example in the book rehashes the old example by Bjarne Stroustrup in his TC++PL book. The danger is there but in a slightly different form. Consider:
>
>short x;
>bump(x);
>
>*This* is the wrong/dangerous code because it silently increments a temporary generated from x, whereas the user may think it increments x. On the other hand, the code
>
>bump(5);
>
>is less dangerous because the user is unlikely to believe they incremented the literal 5 such that writing 5 again will actually mean 6! (Crazy as it sounds, something like that happens in Smalltalk. Ew.)
>
>So converting rvalues to references is fine AS LONG AS the rvalues don't originate from lvalues of a different type.
>
Ok, this makes sense.  Again, I was playing devil's advocate here ;)

Some more arguments from the prince of darkness:  What about properties?  We now will have this possibility:

x.y++; // y is an rvalue property

or at least

bump(x.y);

My thought is that the compiler really has no way to determine if the property is an effective lvalue (i.e. a range which has references in it, but itself is not really an lvalue), so restricting this for the benefit of preventing such situations is not worth the damage to other valid situations.


> Issue 2:
>>
>> Another reason I remember you stating as to why rvalues cannot bind to ref is that it's not the most efficient semantics. So if rvalues bind to both non-ref and ref, can you have overloads between ref and non-ref for optimization purposes?
>>
>> Note that this is *valid* code with 2.058 (and probably many previous
>> compilers):
>>
>> import std.stdio;
>>
>> void foo(ref int x) { writeln("ref"); }
>> void foo(int x) { writeln("nonref"); }
>>
>> void main()
>> {
>> int x;
>> foo(x);
>> foo(5);
>> }
>>
>> prints:
>> ref
>> nonref
>>
>> Will this still compile under the new rules, or will it be ambiguous?
>>
>> -----------------------------
>
>This code should continue to compile under the new rules. A library writer should be able to distinguish rvalues from lvalues.
>
>Excellent!


>> Issue 3:
>>
>> The point that you cannot take an address of a ref value is going to cause a *lot* of existing code to fail. I don't really like this rule for code that isn't marked @safe (which should disallow taking addresses anyway). It seems overly restrictive, and it will be viral in nature. I know you mentioned this is the "long term plan", are the other parts of this severable from this? Is the plan to implement this right now or later? Can you explain why the existing requirements that you don't use pointers in @safe code isn't enough?
>>
>> -Steve
>>
>>
>> _______________________________________________
>
>It is true that the new rule will break code. Walter and I assess that the amount of breakage will be, however, small. Even in today's C++ it is poor style to take the address of reference variables and sneak the resulting pointer. Though sometimes this is necessary in C++, we think it already is much less so in D.
>
>
My largest concern is with &this, as you outlined.  Since you cannot specify that a method accepts 'this' as a pointer, it's almost impossible to write methods for things like linked lists.

However, due to the advent of UFCS, I see some light at the end of the tunnel.  In any case, we *must* have a way to override this behavior, if it's not allowed even in un-@safe code.  If it's restricted to @safe code, we need no workaround, the code is clearly un-@safe.



>Walter likes the idea that we first introduce the restriction in @safe
>code alone. I think we must eventually introduce it for all code, and my
>understanding is that Walter is also convinced of that.
>This is good, I think it's the right path.  My opinion is that it only belongs in @safe code.

One other issue I just thought of that's related to this is delegates.  A delegate to a struct member function effectively stores a reference to the instance, will it be allowed?  Perhaps only as a scope parameter?  I think not allowing this would be a crippling restriction, but allowing it would make this rule have a lot less teeth.


-Steve


April 12, 2012
Le 2012-04-11 à 0:56, Andrei Alexandrescu a écrit :

> On 4/10/12 11:50 PM, Jonathan M Davis wrote:
>> 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?
> 
> Except when an implicit conversion is in the mix, yes. It's conversions and escapes that spoil things. We disallow conversion results to bind to ref and abolish ref escapes altogether, so I think we should be fine.

Speaking of ref escapes, perhaps it'd be a good time to remind ourselves of this hole:

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

	ref int bar()
	{
		int i;
		return foo(i);
	}

	void main()
	{
		bar() += 1; // what are we incrementing again?
	}

The way ref will work now makes makes it possible to define bar like this instead, which would result in the same generated code:

	ref int bar()
	{
		return foo(1);
	}

Now the problem is a little more hidden from sight.

I don't see that as a problem of the new ref behaviour (which I like), but since we're looking at ref semantics I thought it'd be good to have a reminder that there's still an important hole related to ref in need of some attention.

<http://d.puremagic.com/issues/show_bug.cgi?id=3925>


-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/



_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 12, 2012
On 4/12/12, Max Samukha <maxsamukha@gmail.com> wrote:
> I think the language should allow taking addresses of references in unsafe context. One valid and fairly frequent case is passing the address to C:
>
> extern(C) external_foo(S* s);
>
> void foo(ref S s)
> {
>      external_foo(&s);
> }
>

FWIW You can actually use 'ref' in an extern(C) function:
extern(C) external_foo(ref S s);

wxD uses it.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 12, 2012
On Thursday, April 12, 2012 18:53:41 Andrej Mitrovic wrote:
> On 4/12/12, Max Samukha <maxsamukha@gmail.com> wrote:
> > I think the language should allow taking addresses of references in unsafe context. One valid and fairly frequent case is passing the address to C:
> > 
> > extern(C) external_foo(S* s);
> > 
> > void foo(ref S s)
> > {
> > 
> > external_foo(&s);
> > 
> > }
> 
> FWIW You can actually use 'ref' in an extern(C) function:
> extern(C) external_foo(ref S s);
> 
> wxD uses it.

Which I would have expected to be illegal, but for some bizarre reason, the compiler allows it.

http://d.puremagic.com/issues/show_bug.cgi?id=7854

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 12, 2012
On 4/12/12, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> Which I would have expected to be illegal, but for some bizarre reason, the compiler allows it.
>
> http://d.puremagic.com/issues/show_bug.cgi?id=7854


Without that ability, or without the ability to use pointers to
references (which currently works), writing wrapper code to C/C++
libraries is going to be difficult.
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta

April 12, 2012
On Thursday, April 12, 2012 20:00:33 Andrej Mitrovic wrote:
> On 4/12/12, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> > Which I would have expected to be illegal, but for some bizarre reason,
> > the
> > compiler allows it.
> > 
> > http://d.puremagic.com/issues/show_bug.cgi?id=7854
> 
> Without that ability, or without the ability to use pointers to references (which currently works), writing wrapper code to C/C++ libraries is going to be difficult.

Why do you need more than just normal pointers? Because of this proposal making taking the address of a ref illegal? If anything, I think that the need to be able to pass the address of refs to C functions is a good example of why @system code should still be able to take the address of refs.

- Jonathan M Davis
_______________________________________________
dmd-beta mailing list
dmd-beta@puremagic.com
http://lists.puremagic.com/mailman/listinfo/dmd-beta