June 22, 2015
On Monday, 22 June 2015 at 06:38:57 UTC, Andrei Alexandrescu wrote:
> On 6/21/15 11:31 PM, Andrei Alexandrescu wrote:
>> On 6/21/15 10:25 PM, Walter Bright wrote:
>>> The idea is that fun(5) would be lowered to:
>>>
>>>     auto tmp = 5;
>>>     fun(tmp);
>>
>> I don't think that lowering is recommended - it prolongs the lifetime of
>> the temporary through the end of the caller. But that may be actually a
>> good thing.
>
> On second thought - Walter's lowering, which makes the rvalue last more than strictly necessary, may be the most flexible of all at the cost of more resource consumption (for types that define destructors). -- Andrei

I would think in the general case, the variable would need to stick around until the statement was completed in order to avoid problems with it going away prematurely, though maybe the recent changes with return as an attribute fix that problem. But as long as its legal for the function to return an auto ref argument via ref or auto ref, keeping the variable around for the duration of the call - or even just the expression - rather than the statement would risk using the variable after it was destroyed.

- Jonathan M Davis
June 22, 2015
On Monday, 22 June 2015 at 06:38:57 UTC, Andrei Alexandrescu wrote:
> On 6/21/15 11:31 PM, Andrei Alexandrescu wrote:
>> On 6/21/15 10:25 PM, Walter Bright wrote:
>>> The idea is that fun(5) would be lowered to:
>>>
>>>     auto tmp = 5;
>>>     fun(tmp);
>>
>> I don't think that lowering is recommended - it prolongs the lifetime of
>> the temporary through the end of the caller. But that may be actually a
>> good thing.
>
> On second thought - Walter's lowering, which makes the rvalue last more than strictly necessary, may be the most flexible of all at the cost of more resource consumption (for types that define destructors). -- Andrei

Why would that be desirable? Resource consumption is the least of the problems. It is simply surprising, inconsistent with the lifetime of other temporaries, and it is unnecessary. Just lower it to:

    {
        auto tmp = 5;
        fun(tmp);
    }
June 22, 2015
On Monday, 22 June 2015 at 10:04:28 UTC, Marc Schütz wrote:
> On Monday, 22 June 2015 at 06:38:57 UTC, Andrei Alexandrescu wrote:
>> On 6/21/15 11:31 PM, Andrei Alexandrescu wrote:
>>> On 6/21/15 10:25 PM, Walter Bright wrote:
>>>> The idea is that fun(5) would be lowered to:
>>>>
>>>>     auto tmp = 5;
>>>>     fun(tmp);
>>>
>>> I don't think that lowering is recommended - it prolongs the lifetime of
>>> the temporary through the end of the caller. But that may be actually a
>>> good thing.
>>
>> On second thought - Walter's lowering, which makes the rvalue last more than strictly necessary, may be the most flexible of all at the cost of more resource consumption (for types that define destructors). -- Andrei
>
> Why would that be desirable? Resource consumption is the least of the problems. It is simply surprising, inconsistent with the lifetime of other temporaries, and it is unnecessary. Just lower it to:
>
>     {
>         auto tmp = 5;
>         fun(tmp);
>     }

I see now that Andrei already wrote in the PR "creating a named temporary in a scope immediately enclosing the call". I would like to add that AFAIK other temporaries live until the end of the entire statement they appear in, not just for the duration of the call. In any case, the temporaries involved here should not behave different from normal temporaries; in particular, they should have the same lifetime as with pass-by-value.
June 22, 2015
On Monday, 22 June 2015 at 04:11:41 UTC, Andrei Alexandrescu wrote:
> Walter and I discussed what auto ref for templates should look like and reached the conclusion that an approach based on lowering would be best. I added a proposed lowering to https://github.com/D-Programming-Language/dmd/pull/4717.

I have to concur with Manu's statement in the PR. IMO `auto ref` (i.e. the status quo) is a hack introduced because of the lack of usable `scope`. We shouldn't spread it to other parts of the language, at least not for rvalue references. `scope ref` is the perfect fit for those.

(There may still be a use for `auto ref` with the meaning "pass this as efficiently as possible, I don't care whether it's a reference or not", but I'm not convinced of that either.)
June 22, 2015
On Monday, 22 June 2015 at 13:23:47 UTC, Marc Schütz wrote:
> On Monday, 22 June 2015 at 04:11:41 UTC, Andrei Alexandrescu wrote:
>> Walter and I discussed what auto ref for templates should look like and reached the conclusion that an approach based on lowering would be best. I added a proposed lowering to https://github.com/D-Programming-Language/dmd/pull/4717.
>
> I have to concur with Manu's statement in the PR. IMO `auto ref` (i.e. the status quo) is a hack introduced because of the lack of usable `scope`. We shouldn't spread it to other parts of the language, at least not for rvalue references. `scope ref` is the perfect fit for those.
>
> (There may still be a use for `auto ref` with the meaning "pass this as efficiently as possible, I don't care whether it's a reference or not", but I'm not convinced of that either.)

I'm afraid that I don't understand this. What on earth does scope have to do with this issue? We need a way to indicate that a parameter should accept both lvalues and rvalues. auto ref was supposed to do that originally, but Walter misunderstood what Andrei was proposing and implemented what we have now, which is great for forwarding, but it doesn't solve the general case, because it only works with templates. That means that if we want that functionality we then need to either implement auto ref for non-templated functions as originally intended, or we need to come up with a new attribute which does that and which could be used with both templated and non-templated functions (thus not requiring the extra template bloat of the current auto ref implementation with templates if all you want is to accept both lvalues and rvalues, not have the refness of the argument forwarded).

What on earth does _any_ of that have to do with scope? Theoretically, scope indicates that a variable isn't supposed to escape the function - whatever that really means (it's never actually been defined outside of delegates, and even there, I'm not sure that it's defined all that well). What does that have to do with accepting lvalues or rvalues?

- Jonathan M Davis
June 22, 2015
On 22 June 2015 at 23:49, Jonathan M Davis via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Monday, 22 June 2015 at 13:23:47 UTC, Marc Schütz wrote:
>>
>> On Monday, 22 June 2015 at 04:11:41 UTC, Andrei Alexandrescu wrote:
>>>
>>> Walter and I discussed what auto ref for templates should look like and reached the conclusion that an approach based on lowering would be best. I added a proposed lowering to https://github.com/D-Programming-Language/dmd/pull/4717.
>>
>>
>> I have to concur with Manu's statement in the PR. IMO `auto ref` (i.e. the status quo) is a hack introduced because of the lack of usable `scope`. We shouldn't spread it to other parts of the language, at least not for rvalue references. `scope ref` is the perfect fit for those.
>>
>> (There may still be a use for `auto ref` with the meaning "pass this as efficiently as possible, I don't care whether it's a reference or not", but I'm not convinced of that either.)
>
>
> I'm afraid that I don't understand this. What on earth does scope have to do with this issue? We need a way to indicate that a parameter should accept both lvalues and rvalues.

This is what I don't understand; why does this have anything to do
with rvalues/lvalues specifically?
An rvalue is just a temporary. It can safely be passed to anything
that we can be sure won't keep a reference to it; that's why escape
analysis seems to be the best approach.
This problem extends beyond rvalues, there are other forms of
temporaries which exhibit the exact same problem, ie, an rvalue
written to the stack explicitly on the line prior to the function
call:

f(vec3(1,2,3)); // onoes, comple error!

vec3 v = vec3(1,2,3);
f(v); // no worries bro!

This is accepted today, but the safety of the operation is identical
to the rejected line above. This is the de facto means to 'work
around' the problem, and it's just a pointless nuisance.
Both problems should be dealt with in the same way.

> auto ref was supposed to do that originally, but
> Walter misunderstood what Andrei was proposing and implemented what we have
> now, which is great for forwarding, but it doesn't solve the general case,
> because it only works with templates. That means that if we want that
> functionality we then need to either implement auto ref for non-templated
> functions as originally intended, or we need to come up with a new attribute
> which does that and which could be used with both templated and
> non-templated functions (thus not requiring the extra template bloat of the
> current auto ref implementation with templates if all you want is to accept
> both lvalues and rvalues, not have the refness of the argument forwarded).

It's been proposed repeatedly for years. 'scope' as a means of expressing borrowing or escape analysis would solve the problem elegantly, in addition to other uses.

There was also an idea Walter had at dconf 13, where he could do runtime checking similar to range checking for safety validation, thereby allowing unqualified ref args to receive temporaries safely.

> What on earth does _any_ of that have to do with scope? Theoretically, scope indicates that a variable isn't supposed to escape the function - whatever that really means (it's never actually been defined outside of delegates, and even there, I'm not sure that it's defined all that well). What does that have to do with accepting lvalues or rvalues?

If a parameter was scope, it can safely receive an rvalue.

June 22, 2015
On 6/22/15 3:04 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
> Just lower it to:
>
>      {
>          auto tmp = 5;
>          fun(tmp);
>      }

You need to lower an expression to an expression, not a statement. (e.g. what if fun returns a result?)

I considered this lowering for "int fun(ref int);"

fun(42)

==>>

(function int(int a) { return fun(a); })(42)

This does work, but if fun returns a ref int, I found no way to syntactically express that lambda. This does not parse:

(function ref int(int a) { return fun(a); })(42)

Is this a bug in the grammar?


Andrei

June 22, 2015
Rather than raising the matter of scope again and again, we should be thankful that a solution for this nasty problem is accepted and could be merged. How scope and escape analysis could do a better job is unclear and if you want to solve the problem this way you will wait a very long time. So please let us concentrate and discuss how we could solve this problem with auto ref. :)

To repeat my statement from the PR:
I would also prefer to avoid the generation of further functions, because I want to avoid the code bloat. I like the way of the current implementation, because it is following the way C++ does and will be understandable for every person which comes from C++.
June 22, 2015
On Monday, 22 June 2015 at 13:49:31 UTC, Jonathan M Davis wrote:
> On Monday, 22 June 2015 at 13:23:47 UTC, Marc Schütz wrote:
>> On Monday, 22 June 2015 at 04:11:41 UTC, Andrei Alexandrescu wrote:
>>> Walter and I discussed what auto ref for templates should look like and reached the conclusion that an approach based on lowering would be best. I added a proposed lowering to https://github.com/D-Programming-Language/dmd/pull/4717.
>>
>> I have to concur with Manu's statement in the PR. IMO `auto ref` (i.e. the status quo) is a hack introduced because of the lack of usable `scope`. We shouldn't spread it to other parts of the language, at least not for rvalue references. `scope ref` is the perfect fit for those.
>>
>> (There may still be a use for `auto ref` with the meaning "pass this as efficiently as possible, I don't care whether it's a reference or not", but I'm not convinced of that either.)
>
> I'm afraid that I don't understand this. What on earth does scope have to do with this issue? We need a way to indicate that a parameter should accept both lvalues and rvalues.

`scope` is a precondition for doing this safely. As Manu pointed out, rvalues are merely a special case of a more general problem, but with them, the risk of misuse is much higher than with local variables. That was probably the reason why `ref` originally was designed not to accept rvalues. Given a working `scope` feature, that reason is no longer relevant, therefore `scope ref` can safely accept both rvalues and lvalues.
June 22, 2015
On Monday, 22 June 2015 at 15:39:38 UTC, Andrei Alexandrescu wrote:
> On 6/22/15 3:04 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm@gmx.net>" wrote:
>> Just lower it to:
>>
>>      {
>>          auto tmp = 5;
>>          fun(tmp);
>>      }
>
> You need to lower an expression to an expression, not a statement. (e.g. what if fun returns a result?)
>
> I considered this lowering for "int fun(ref int);"
>
> fun(42)
>
> ==>>
>
> (function int(int a) { return fun(a); })(42)
>
> This does work, but if fun returns a ref int, I found no way to syntactically express that lambda. This does not parse:
>
> (function ref int(int a) { return fun(a); })(42)
>
> Is this a bug in the grammar?

Probably. But for lowering, the resulting AST doesn't really need to be representable in the language's syntax. I'm sure the AST _can_ express a lambda returning by reference.

Anway, I really think we should not deviate from the normal lifetime rules for temporaries.