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 <ki...@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. :) >