[dmd-beta] rvalue references

Andrei Alexandrescu andrei at erdani.com
Sat Apr 14 21:11:18 PDT 2012


On 4/13/12 3:47 AM, kenji hara wrote:
> I think the main purpose of rvalue reference is:
> "Called function requires the address of given value, but not need to
> change its value semantics."

I think it's a good way to look at it, but there's sometimes something
like this: "This function doesn't care rvalue vs. lvalue, but doesn't
want to mess with const and would prefer pass by ref wherever possible
for efficiency reasons."

> We can never rewrite basic literals, therefore we can say that they
> have constant value semantics, even if their types are mutable. And
> then, it seems that rewriting literal through rvalue reference (==
> temporary variable) is counter-intuitive, and less useful.
> On the other hand, compound literals usually have mutable
> elements/fields, so called function may use and rewrite them. It is
> often useful.

Correct. One detail is that basic literals are obviously not modifiable
at the call site: foo(2, 3.4) is visibly unable to modify its arguments.
But then, in fairness, foo(a, b) is more confusing if a and b are enum
values.

> More details of my proposal with an actual code:
> 
> struct S{}
> 
> void foo(const ref int v){}
> void foo(const ref double v){}
> void foo(const ref cdouble v){}
> void foo(const ref int[] v){}
> void foo(const ref int[int] v){}
> void foo(const ref S v){}
> void bar(      ref int v){}
> void bar(      ref double v){}
> void bar(      ref cdouble v){}
> void bar(      ref int[] v){}
> void bar(      ref int[int] v){}
> void bar(      ref S v){}
> 
> void hoo(T)(const ref T v){}
> void var(T)(      ref T v){}
> 
> void main()
> {
>      // cannot bind basic literals to mutable ref
>      enum int ei = 1024;
>      foo(1024);  static assert(!__traits(compiles, bar(1024)));
>      hoo(1024);  static assert(!__traits(compiles, var(1024)));
>      foo(ei);    static assert(!__traits(compiles, bar(ei)));
>      hoo(ei);    static assert(!__traits(compiles, var(ei)));

Fine.

>      enum double ef = 3.14;
>      foo(3.14);  static assert(!__traits(compiles, bar(3.14)));
>      hoo(3.14);  static assert(!__traits(compiles, var(3.14)));
>      foo(ef);    static assert(!__traits(compiles, bar(ef)));
>      hoo(ef);    static assert(!__traits(compiles, var(ef)));
> 
>      enum cdouble ec = 1+1i;
>    /*foo(1+1i);*/static assert(!__traits(compiles, bar(1+1i)));
>    /*hoo(1+1i);*/static assert(!__traits(compiles, var(1+1i)));
>      foo(ec);    static assert(!__traits(compiles, bar(ec)));
>      hoo(ec);    static assert(!__traits(compiles, var(ec)));

So far so good.

>      // can bind compound literals to mutable ref
>      enum int[] ea = [1,2];
>      foo([1,2]); bar([1,2]);
>      hoo([1,2]); var([1,2]);
>      foo(ea);    bar(ea);
>      hoo(ea);    var(ea);
> 
>      enum int[int] eaa = [1:1];
>      foo([1:1]); bar([1:1]);
>      hoo([1:1]); var([1:1]);
>      foo(eaa);   bar(eaa);
>      hoo(eaa);   var(eaa);
> 
>      enum S es = S();
>      foo(S());   bar(S());
>      hoo(S());   var(S());
>      foo(es);    bar(es);
>      hoo(es);    var(es);
> }

This makes sense, but there are two issues:

1. How about generic code? Generic code should have a "use the most
efficient passing convention for this argument, I'm okay with either
value or reference".

2. What if the rvalue is the result of calling a function? Does it bind
to mutable ref or not?

It became clear to me that Walter and my initial proposal is not good.
But I'm not sure we have a clear and simple vision yet.



Andrei


More information about the dmd-beta mailing list