auto ref is on the docket

kinke via Digitalmars-d digitalmars-d at puremagic.com
Sat Jun 27 06:46:26 PDT 2015


On Saturday, 27 June 2015 at 11:10:49 UTC, Marc Schütz wrote:
> On Saturday, 27 June 2015 at 01:18:19 UTC, Jonathan M Davis 
> wrote:
>> That's a completely orthogonal issue to ref or auto ref. 
>> That's an @system operation (since taking the address of a 
>> local variable is @system), and it's up to you to not screw it 
>> up. scope might cover that if it were fully ironed out, since 
>> that does involve escaping, but it also might not, since it's 
>> an @system operation and thus up to you not to screw it up.
>
> The point is that with scope, it _doesn't_ need to be @system 
> anymore.
>
>> Regardless, it has nothing to do with whether the function 
>> accepts lvalues and rvalues with the same parameter. You have 
>> a safety issue regardless if you're talking about taking a 
>> pointer to an argument (or to some portion of the argument), 
>> since there's no guarantee that the lifetime of the pointer is 
>> shorter than that of the argument.
>
> No, not with scope. [...] the problems you mention will no 
> longer exist with scope.

Exactly, that's the whole point.
The relation with lvalue/rvalue reference parameters is that the 
compiler should be able to statically detect and refuse escaping 
rvalue bugs. Escaping lvalues with potential for dangling 
pointers should be @system only, but preventing those bugs is a 
whole different beast.

Still, to make (a) taking the address of ref params, locals & 
globals and (b) using pointer params @safe, the compiler needs to 
know whether the parameter escapes or not. I tend to let the 
compiler figure that out in the future rather than having to use 
`scoped` a lot for ref and pointer params.

>> We introduced the return attribute (currently only with 
>> -dip25) to fix this problem. So, with that, we eliminate the 
>> safety problem with ref itself, and we can safely have auto 
>> ref accept rvalues by having it assign them to a temporary 
>> variable first.
>
> Yes this is now possible, but why in all world do you want the 
> keyword that enables it to be `auto ref`?

Exactly. For a function returning a ref parameter, it doesn't 
matter whether it's an rvalue or lvalue. The important thing is 
to propagate that distinction (automatically by the compiler), to 
disallow binding a returned rvalue reference to an escaping ref 
parameter (i.e., no `escape(forward(S(1)))`).
Where the distinction between lvalues and rvalues matters for a 
function returning a ref parameter, as for any other function 
with ref params, is whether the parameter escapes (i.e., by 
storing a pointer somewhere). If it does, it should be `return 
ref`, otherwise `return scope ref` (either explicitly or inferred 
automatically by the compiler).

>> Any issues with taking pointers to arguments is firmly in 
>> @system territory and is thus completely orthogonal. Even if 
>> scope were to be implemented in a way that prevented it, it 
>> would still have nothing to do with whether the function 
>> accepted both rvalues and lvalues with the same parameter.

Of course it would if one made actually use of a scope system 
(again, either explicit or as a result of compiler escape 
analysis) to (a) rule out all escaping rvalue bugs and (b) 
possibly warn about or highlight escaping lvalue params in 
@system code. The main aim of the scope system would be to 
enhance the flexibility of @safe code though.

>>> In the meantime, what about making all `ref` params accept 
>>> rvalues
>>
>> Please, please, no. ref indicates that your intention is to 
>> mutate the argument. Having it accept rvalues completely 
>> destroys that and makes it that much harder to understand what 
>> a function is supposed to do.

If that was the only reason for not accepting rvalues as `ref` 
params, then rvalues should have been allowed for `const ref` 
right from the beginning, as there's surely absolutely no 
intention to mutate a `const ref` argument.

> I can accept that argument, although I see cases where it's 
> still justified. For example, if the author of the function 
> decided it wants to mutate the argument, but you (the caller) 
> are not interested in the new value. But still, explicitly 
> using a temporary named `dummy` is preferable because it even 
> documents that you're going to ignore it.

I find letting the callee decide whether the caller needs to 
provide an lvalue (`ref`) or not (non-templated `auto ref`), 
based solely on making sure the mutations are directly visible by 
the caller after the call, too much. I think it should be left to 
the caller to decide what mutations it's interested in.

But now I see why some would oppose calling that `scope ref`, as 
that really has nothing to do with scope or safety, that'd just 
be an arbitrary way of classifying ref params in 'essential 
output' (mutable lvalue `ref`s, mutations need to be visible by 
caller) and some other category (lvalue/rvalue `auto ref`s, not 
just for efficiency purposes). That really is an orthogonal and 
incompatible semantic compared to what `scope ref` is all about, 
and doesn't interest me at all. I find flexible @safe code and 
detecting escaping bugs a kazillion times more important than 
making sure a caller sees all mutations the callee deems 
essential after the call.


More information about the Digitalmars-d mailing list