rvalues -> ref (yup... again!)

John Colvin john.loughran.colvin at gmail.com
Sat Mar 24 23:03:36 UTC 2018


On Saturday, 24 March 2018 at 17:30:35 UTC, Manu wrote:
> On 24 March 2018 at 04:57, John Colvin via Digitalmars-d 
> <digitalmars-d at puremagic.com> wrote:
>> On Friday, 23 March 2018 at 22:01:44 UTC, Manu wrote:
>>>
>>> Forked from the x^^y thread...
>>>
>>> On 23 March 2018 at 12:16, Walter Bright via Digitalmars-d 
>>> <digitalmars-d at puremagic.com> wrote:
>>>>
>>>> On 3/23/2018 11:09 AM, Manu wrote:
>>>>>
>>>>>
>>>>> [...]
>>>>
>>>>
>>>> Rvalue references are not trivial and can have major 
>>>> unintended consequences. They're a rather ugly feature in 
>>>> C++, with weirdities. I doubt D will ever have them.
>>>
>>>
>>> Can you please explain these 'weirdities'?
>>> What are said "major unintended consequences"?
>>> Explain how the situation if implemented would be any 
>>> different than
>>> the workaround?
>>>
>>> This seems even simpler than the pow thing to me.
>>> Rewrite:
>>>     func(f());
>>> as:
>>>     { auto __t0 = f(); func(__t0); }
>>>
>>
>> I understand what you want, but I'm struggling to understand 
>> why it's such a huge deal.
>
> Because it makes this kind of D code that interacts with C++
> objectively worse than C++, and there's no reason for it.
> You can't say to someone who just frustrated-ly doubled their 
> line
> count by manually introducing a bunch of temporaries in a tiny
> function that appears to do something so simple as 'call a 
> function',
> that "oh yeah, isn't it cool that you can't just call your 
> functions
> anymore! isn't D cool! we should switch to D right?"
> It's embarrassing. I've been put in the position where I have 
> to try
> and 'explain' this feature quite some number of times... they 
> usually
> just give me 'the look'™; ya know, quietly wondering if I'm 
> still
> sane, and all I end up with is someone who's about 95% less 
> convinced
> that D is cool than they were 5 seconds beforehand.
> What pisses me off is that's such a pointless thing to happen, 
> because
> this issue is so trivial!
>
> In my experience, people are evaluating how D will materially 
> impact
> the exact same code they're already writing in C++. This is one 
> of
> those ways that they will be materially impacted, and it's 
> almost
> enough all on its own to cause people to dismiss the entire 
> thing on
> the spot.
> Pretty much the best case at this phase is that the D code is 
> exactly
> the same as C++. If we can trim off a few parens here and there
> (ufcs?), maybe remove some '::' operators (modules that don't 
> suck),
> that's a huge win.
>
>
>> The reason you want to pass by reference is for performance, 
>> to avoid copying the data at the call boundary.
>>
>> So there are 2 cases: an lvalue needs to be passed, or an 
>> rvalue needs to be passed.
>>
>> 1. The address of the lvalue is passed.
>>
>> 2. The rvalue is copied to a local, then the address of that 
>> local is passed.
>>
>> So in the rvalue case, you're not getting the performance 
>> benefit of passing by reference, because you have to copy to a 
>> local anyway.
>>
>> What I would do in D currently to get the same performance and 
>> API:
>>
>> void foo(float[32] v) { foo(v); }
>> void foo(ref float[32] v) { ... }
>>
>> or
>>
>> void foo()(auto ref float[32] v) { ... }
>
> Can't be extern(C++), can't be virtual either (both is likely).
> I said before; you're talking about Scott Meyers 'universal
> references' as a language concept, and I'm just talking about 
> calling
> a function.
>
>
>> but I dont' get how or why. It's exactly D's solution to the 
>> problem.
>
> It doesn't solve the problem... it doesn't even address the 
> problem. You're talking about a totally different thing >_<
>

Auto ref allows the unnecessary copy to be avoided for lvalues 
and creates a temporary (as part of passing the value) for 
rvalues. It has downsides (virtual functions and extern(C++), but 
it does directly address the problem you're talking about, unless 
I have totally misunderstood you.

Here is a small proof of concept I made to demonstrate how easy 
it seems to be to use `auto ref` to call a C++ virtual const& 
function without incurring any more copies than would happen with 
the same calls from C++. I'm sure it could be improved a lot, but 
does the basic concept match what you would need?

// D source file:

/// mix this in to your extern(C++) class with a list of the 
functions where you
/// want to be able to pass rvalues to ref parameters.
auto rValueRefCalls(Funcs ...)()
{
     string ret;
     foreach (foo; Funcs)
         ret ~= `extern(D) void ` ~ __traits(identifier, foo) ~ 
`(Args ...)(auto ref Args args)
     if (__traits(compiles, (&this.` ~ __traits(identifier, foo) ~ 
`)(args)))
     {
         (&this.foo)(args);
     }`;

     return ret;
}

extern(C++)
{
     class A
     {
         void foo(const ref int v);
         mixin(rValueRefCalls!foo);
     }

     A makeA();
}

void main()
{
     int x = 3;
     auto a = makeA();
     a.foo(x);
     a.foo(3);
}


// C++ source file:

#include<cstdio>

class A
{
public:
     virtual void foo(const int& v)
     {
         printf("%d\n", v);
     }
};

A *makeA()
{
     return new A;
}



More information about the Digitalmars-d mailing list