October 19, 2016
On 10/19/2016 2:11 AM, Ethan Watson wrote:
> On Wednesday, 19 October 2016 at 05:41:17 UTC, Manu wrote:
>> People just want to be able to do this:
>>
>>   void f(ref const(Vector) v);
>>
>>   f(v1 + v2);
>>
>> or:
>>
>>   f(Vector(10,20,30));
>>
>> That is all. The rval produces a temporary, and the temporary is passed to the
>> function.
>
> Probably worth pointing out that we laid it out exactly like this to Walter and
> Andrei at DConf, and how not having it made the Quantum Break animation code
> (all of which is 3D math) a pain to write thanks to having to define the
> temporary variables yourself. Especially when you're calling bound C++ functions
> and the programmers involved could compare it to C++ directly saying "Why can't
> we do this?"


  void f(ref Vector v);
  void fv(Vector v) { f(v); }

  fv(Vector(10,20,30));

fv gets inlined, so no overhead.
October 19, 2016
Better:

   void f(ref Vector v);
   void f(Vector v) { f(v); }

   f(Vector(10,20,30));

October 19, 2016
On 10/19/16 5:11 AM, Ethan Watson wrote:
> On Wednesday, 19 October 2016 at 05:41:17 UTC, Manu wrote:
>> People just want to be able to do this:
>>
>>   void f(ref const(Vector) v);
>>
>>   f(v1 + v2);
>>
>> or:
>>
>>   f(Vector(10,20,30));
>>
>> That is all. The rval produces a temporary, and the temporary is
>> passed to the function.
>
> Probably worth pointing out that we laid it out exactly like this to
> Walter and Andrei at DConf, and how not having it made the Quantum Break
> animation code (all of which is 3D math) a pain to write thanks to
> having to define the temporary variables yourself. Especially when
> you're calling bound C++ functions and the programmers involved could
> compare it to C++ directly saying "Why can't we do this?"

"Because you're trying to write C++ in D." :o)

I'm just kidding. I agree it's occasionally unpleasant to have the calling convention impose l/rvalueness depending on by ref/by value signature. With the recent tightening of ref semantics, and if we carefully navigate around C++'s mistake, we may be able to define a way to meaningfully bind rvalues to ref. It's a fair amount of work, worth a thorough DIP. Implementation is the easy part (for the most part lifting restrictions).


Andrei


October 19, 2016
On 10/19/16 1:47 AM, Manu via Digitalmars-d wrote:
> On 19 October 2016 at 06:22, Andrei Alexandrescu via Digitalmars-d
> <digitalmars-d@puremagic.com <mailto:digitalmars-d@puremagic.com>> wrote:
>
>     On 10/18/2016 04:15 PM, Atila Neves wrote:
>
>
>         I think I get it; I'm just not sure given the comments that pop
>         up in
>         the forum. Isn't one of the main reasons distinguishing between
>         these two?
>
>         void fun(ref const Foo);
>         void fun(Foo);
>
>         If they can't be distinguished, you don't get move semantics
>         "for free".
>
>
>     That's right, thanks Atila. -- Andreu
>
>
> This is obvious though, lval calls the first, rval calls the second.
> Surely most programmers would intuitively expect that behaviour? Is
> there some issue there?

You're missing context. The conversation went like this:

Jonathan: `Andrei said rvalue references were a mistake in C++'

Andrei: `No, I said binding rvalues to const& was a mistake of C++, which subsequently led to the necessity of rvalue references.'

Atila: `Indeed, if you cannot distinguish between void fun(ref const Foo) and void fun(Foo) then you're going to have a bad time.'

(NOTA BENE: at this point it became unclear whether we discuss C++ or hypothetical D code. Atila used D syntax in a discussion about C++'s issue.)

Me: `Affirmative.'

You: `But wait, it's intuitive: lvalues bind to the first, rvalues bind to the last.'

Well, I'd agree it's intuitive but C++ won't allow it. These overloads are ambiguous in C++ code:

==============
struct S {};
void foo(S);
void foo(const S&); // no error so far (which doesn't help either)

int main() {
    S a;
    foo(a); // ERROR! Ambiguous call!
    const S b;
    foo(b); // ERROR! Ambiguous call!
    foo(S()); // ERROR! Ambiguous call!
    extern const S goo();
    foo(goo()); // ERROR! Ambiguous call!
}
==============

This was C++'s big un' that led to many complications. If the overload weren't ambiguous, a large part of rvalue references would have been unneeded. (Universal references would still have been necessary for perfect forwarding, but that's not the bulk.)

In order to avoid such issues, we steered clear off binding rvalues to ref parameters in the D language. As I mentioned to Ethan, I do agree a careful definition may be able to avoid the fallout that happened in C++. It would be a fair amount of work.


Andrei

October 19, 2016
On Wednesday, October 19, 2016 07:55:19 Andrei Alexandrescu via Digitalmars-d wrote:
> This was C++'s big un' that led to many complications. If the overload weren't ambiguous, a large part of rvalue references would have been unneeded. (Universal references would still have been necessary for perfect forwarding, but that's not the bulk.)
>
> In order to avoid such issues, we steered clear off binding rvalues to ref parameters in the D language. As I mentioned to Ethan, I do agree a careful definition may be able to avoid the fallout that happened in C++. It would be a fair amount of work.

The other big problem is that D's const is so much more restrictive than C++'s that even if const ref accepted rvalues, a large portion of the time, it would be too restrictive to be useful.

- Jonathan M Davis

October 19, 2016
On 10/19/2016 11:38 AM, Jonathan M Davis via Digitalmars-d wrote:
> On Wednesday, October 19, 2016 07:55:19 Andrei Alexandrescu via Digitalmars-d
> wrote:
>> This was C++'s big un' that led to many complications. If the overload
>> weren't ambiguous, a large part of rvalue references would have been
>> unneeded. (Universal references would still have been necessary for
>> perfect forwarding, but that's not the bulk.)
>>
>> In order to avoid such issues, we steered clear off binding rvalues to
>> ref parameters in the D language. As I mentioned to Ethan, I do agree a
>> careful definition may be able to avoid the fallout that happened in
>> C++. It would be a fair amount of work.
>
> The other big problem is that D's const is so much more restrictive than
> C++'s that even if const ref accepted rvalues, a large portion of the time,
> it would be too restrictive to be useful.

That's why if we allow binding rvalues to references, we'd allow it regardless of const. -- Andrei


October 19, 2016
On Tuesday, 18 October 2016 at 06:30:15 UTC, Namespace wrote:
> On Tuesday, 18 October 2016 at 02:54:08 UTC, Manu wrote:
>> I just want to be able to pass an rvalue to a function that receives a
>> const ref... that's why I came to this forum in the first place like,
>> 7 years ago. 7 years later... still can't.
>
> I recently wrote a PR for p0nce D idioms, which shows how you can do that
> https://github.com/p0nce/d-idioms/pull/119

Just wanted to add that I still don't know (I'm lazy) what "auto ref" parameters, "auto ref" return, and friends do in D.
ref is somewhat easy to explain in C++ but complicated in D.
October 19, 2016
On Wednesday, 19 October 2016 at 17:42:39 UTC, Guillaume Piolat wrote:
> On Tuesday, 18 October 2016 at 06:30:15 UTC, Namespace wrote:
>> On Tuesday, 18 October 2016 at 02:54:08 UTC, Manu wrote:
>>> I just want to be able to pass an rvalue to a function that receives a
>>> const ref... that's why I came to this forum in the first place like,
>>> 7 years ago. 7 years later... still can't.
>>
>> I recently wrote a PR for p0nce D idioms, which shows how you can do that
>> https://github.com/p0nce/d-idioms/pull/119
>
> Just wanted to add that I still don't know (I'm lazy) what "auto ref" parameters, "auto ref" return, and friends do in D.
> ref is somewhat easy to explain in C++ but complicated in D.

For each auto ref argument the compiler will lazily generate 2^N functions (therefore "template bloat" if you overdo it). Example:

----
struct A { int id; }
void test(T)(auto ref T a) { }

A a = A(42);
test(a);
----

will generate one function, which takes the argument by ref:
----
void test(ref A a) { }
----

Another call
----
test(A(42));
----

will generate another function, which takes the argument by value:
----
void test(A a) { }
----

That's more ore less the magic behind auto ref.
October 19, 2016
On Wednesday, October 19, 2016 12:48:54 Andrei Alexandrescu via Digitalmars-d wrote:
> On 10/19/2016 11:38 AM, Jonathan M Davis via Digitalmars-d wrote:
> > On Wednesday, October 19, 2016 07:55:19 Andrei Alexandrescu via
> > Digitalmars-d>
> > wrote:
> >> This was C++'s big un' that led to many complications. If the overload weren't ambiguous, a large part of rvalue references would have been unneeded. (Universal references would still have been necessary for perfect forwarding, but that's not the bulk.)
> >>
> >> In order to avoid such issues, we steered clear off binding rvalues to ref parameters in the D language. As I mentioned to Ethan, I do agree a careful definition may be able to avoid the fallout that happened in C++. It would be a fair amount of work.
> >
> > The other big problem is that D's const is so much more restrictive than
> > C++'s that even if const ref accepted rvalues, a large portion of the
> > time,
> > it would be too restrictive to be useful.
>
> That's why if we allow binding rvalues to references, we'd allow it regardless of const. -- Andrei

Which then causes the problem that it becomes much less clear whether ref is supposed to be modifying its argument or is just trying to avoid copying it - though good documentation can mitigate that problem.

- Jonathan M Davis

October 19, 2016
On Wednesday, 19 October 2016 at 18:15:25 UTC, Jonathan M Davis wrote:
> Which then causes the problem that it becomes much less clear whether ref is supposed to be modifying its argument or is just trying to avoid copying it - though good documentation can mitigate that problem.
>
> - Jonathan M Davis

As long as it would be marked with scope (or some similar attribute) so that it cannot escape, it would be fine, wouldn't it?