11/8/2012 11:30 PM, martin пишет:
On Thursday, 8 November 2012 at 18:28:44 UTC, Dmitry Olshansky wrote:
What's wrong with going this route:

void blah(auto ref X stuff){
...lots of code...
}

is magically expanded to:

void blah(ref X stuff){
...that code..
}

and

void blah(X stuff){
    .blah(stuff); //now here stuff is L-value so use the ref version
}

Yeah, it looks _almost_ like a template now. But unlike with a
template we can assume it's 2 overloads _always_. External fucntion
issue is then solved by treating it as exactly these 2 overloads (one
trampoline, one real). Basically it becomes one-line declaration of 2
functions.

Given that temporaries are moved anyway the speed should be fine and
there is as much bloat as you'd do by hand.

Also hopefully inliner can be counted on to do its thing in this
simple case.

That second overload for rvalues would be a shortcut to save the lvalue
declarations at each call site - and it really doesn't matter if the
compiler magically added the lvalue declarations before each call or if
it magically added the rvalue overload (assuming all calls are inlined).

The scope. It's all about getting the correct scope, destructor call and you know, the works. Preferably it can inject it inside temporary scope.

Anticipating bugs in the implementation of this feature let me warn that re-writing this:
... code here ...
auto  r = foo(SomeResource(x, y, ..)); //foo is auto ref
... code here ...

Should not change semantics e.g. imagine the resource is a lock, we'd better unlock it sooner. That is call destructor right after foo returns. So we need {} around the call. But this doesn't work as it traps 'r':

{
auto someRef = SomeResource(x, y, ..);
auto r  = foo(someRef);
}

So it's rather something like this:

typeof(foo(...)) r = void;
{
someRef = SomeResource(x, y, ..);
r = foo(someRef); // should in fact construct in place not assign
}

I suspect this is hackable to be more clean inside of the compiler but not in terms of a re-write.

But it would create a problem if there already was an explicit 'void
blah(X)' overload in addition to 'void blah(auto ref X)' (not making
much sense obviously, but this would be something the compiler needed to
handle somehow).

Aye. But even then there is an ambiguity if there is one version of function with ref T / T and one with auto ref T.

What this 'auto ref' approach (both as currently implemented for
templates and proposed here for non-templated functions) lacks is the
vital distinction between const and mutable parameters.

For the much more common const ref parameters, I repeatedly tried to
explain why I'm absolutely convinced that we don't need another keyword
and that 'in/const ref' is sufficient, safe, logical and intuitive
(coupled with the overload rule that pass-by-value (moving) is preferred
for rvalues). Please prove me wrong.

I'd rather restrict it to 'auto ref' thingie. Though 'in auto ref' sounds outright silly. Simply put const ref implies that callee can save a pointer to it somewhere (it's l-value). The same risk is with 'auto ref' but at least there an explicitly written 'disclaimer' by the author of accepting temporary stuff.

In the ideal world name 'auto ref' would be shorter, logical and more to the point but we have what we have.


For the less common mutable ref parameters, I also repeatedly tried to
explain why I find it dangerous/unsafe to allow rvalues to be bound to
mutable ref parameters. But if there are enough people wanting that, I'd
have no problem with an 'auto ref' approach for it (only for mutable
parameters!). That may actually be a good compromise, what do you guys
think? :)

I think that function plucked with auto ref is a enough indication that author is fine with passing to it mutable r-values and not seeing changes outside and related blah-blah. In most (all?) of cases it means that parameter is too big to be passed by copy so rather it takes it by ref. Also certain stuff can't be properly bitwise const because of C-calls and what not. Logical const is the correct term but in the D world it's simply mutable.


'auto ref T' for templates expands to 'ref T' (lvalues) and 'T'
(rvalues), duplicating the whole function and providing best performance
- no pointer/reference indirection for rvalues in contrast to 'auto ref
T' (proposed above) for non-templates, otherwise the concept would be
exactly the same. But it's only for mutable parameters.

I'd say that even for templates the speed argument is mostly defeated by the bloat argument. But that's probably only me.

Such a templated option may also be worth for const parameters though
(expanding to 'const ref T' and 'const T'), so maybe something like the
(ambiguous) 'in/const auto ref T' wouldn't actually be that bad
(assuming there are only a few use cases, and only for templates! It'd
still be 'in ref T' for non-templates).



--
Dmitry Olshansky

Reply via email to