Settling rvalue to (const) ref parameter binding once and for all

Manu turkeyman at gmail.com
Sat Nov 10 03:05:28 PST 2012


Hear hear!
I have dreams at night that look exactly like this proposal! :)
I think I had one just last night, and woke up with a big grin on my face...

> 2) rvalues: prefer pass-by-value (moving: argument allocated
   directly on callee's stack (parameter) vs. pointer/reference
   indirection implied by pass-by-ref)

Is this actually possible?
Does the C/C++ ABI support such an action? GDC and LDC use the C ABI
verbatim, so can this work, or will they have to, like usual, allocate on
the caller's stack, and pass the ref through. I don't really see a
significant disadvantage to that regardless.


On 9 November 2012 20:05, martin <kinke at libero.it> wrote:

> Hi guys,
>
> I hope you don't mind that I'm starting yet another thread about this
> tedious issue, but I think the other threads are too clogged.
>
> Let me summarize my (final, I guess) proposal. I think it makes sense to
> compare it to C++ in order to anticipate and hopefully invalidate (mainly
> Andrei's) objections.
>
>      parameter type     |   lvalue    |    rvalue
>                         | C++     D   | C++     D
> ------------------------|-----**--------|------------
> T                       | copy   copy | copy   move
> T& / ref T              | ref    ref  | n/a    n/a
> out T (D only)          |        ref  |        n/a
> T&& (C++ only)          | n/a         | move
> auto ref T (D only) (*) |        ref  |        ref
> ------------------------|-----**--------|------------
> const T                 | copy   copy | copy   move
> const T& / const ref T  | ref    ref  | ref    ref (*)
> const T&& (C++ only)    | n/a         | move
>
> (*): proposed additions
>
> For lvalues in both C++ and D, there are 2 options: either copy the
> argument (pass-by-value) or pass it by ref. There's no real difference
> between both languages except for D's additional 'out' keyword and, with
> the proposed 'auto ref' syntax, an (imo negligible) ambiguity between 'ref
> T' and 'auto ref T' in D.
>
> Rvalues are a different topic though. There are 3 possibilites in general:
> copy, move and pass by ref. Copying rvalue arguments does not make sense -
> the argument won't be used by the caller after the invokation, so a copy is
> redundant and hurts performance. D corrects this design flaw of C++ (which
> had to introduce rvalue refs to add move semantics on top of the default
> copy semantics) and therefore only supports moving instead. C++
> additionally supports pass-by-ref of rvalues to const refs, but not to
> mutable refs. I propose to allow pass-by-ref to both const (identical
> syntax as C++, it's perfectly safe and logical) and mutable refs (new
> syntax with 'auto ref' to emphasize that the parameter may be an rvalue
> reference, with related consequences such as potentially missing side
> effects).
>
> Regarding the required overloading priorities for the proposed additions
> to work properly, I propose:
> 1) lvalues: prefer pass-by-ref
>    so: ref/out T -> auto ref T (*) -> const ref T -> (const) T
>    - const lvalues:   const ref T -> (const) T
>    - mutable lvalues: ref/out T -> auto ref T (*) -> const ref T ->
>                       (const) T
> 2) rvalues: prefer pass-by-value (moving: argument allocated
>    directly on callee's stack (parameter) vs. pointer/reference
>    indirection implied by pass-by-ref)
>    so: (const) T -> auto ref T (*) -> const ref T (*)
>
> Finally, regarding templates, I'm in favor of dropping the current 'auto
> ref' semantics and propose to simply adopt the proposed semantics for
> consistency and simplicity and to avoid excessive code bloating. That
> shouldn't break existing code I hope (unless parameters have been denoted
> with 'const auto ref T', which would need to be changed to 'const ref T').
>
> ---
>
> Before posting concerns about a perceived unsafety of binding rvalues to
> 'const ref' parameters, please try to find a plausible argument as to why
> the following is currently allowed:
>
> void foo(const ref T x);
> if (condition)
> {
>     T tmp;
>     foo(tmp);
> } // destruction of tmp
>
> but the following shortcut, eliminating 3 lines (depending on code
> formatting preferences ;)) and avoiding the pollution of the local
> namespace with a 'tmp' variable, shouldn't be allowed:
>
> if (condition)
>     foo(T()); // rvalue destructed immediately after the call
>
> ---
>
> Let me also illustrate a deterministic allocation/destruction scheme for
> the compiler implementation/language specification:
>
> void foo(auto/const ref T a, auto/const ref T b);
>
> foo(T(), T());
> /* order:
>    1) allocate argument a on caller's stack
>    2) allocate argument b on caller's stack
>    3) invoke foo() and pass the argument addresses (refs)
>    4) destruct b
>    5) destruct a
> */
>
> I guess something like that is covered by the C++ specification for
> binding rvalues to const refs.
>
> ---
>
> Now please go ahead and shoot. :)
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20121110/12482bb2/attachment-0001.html>


More information about the Digitalmars-d mailing list