[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