<p>How about my idea, Andrei?</p>
<p>Kenji Hara<br>
</p>
<div class="gmail_quote">2012/04/13 17:47 "kenji hara" <<a href="mailto:k.hara.pg@gmail.com">k.hara.pg@gmail.com</a>>:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I think the main purpose of rvalue reference is:<br>
"Called function requires the address of given value, but not need to<br>
change its value semantics."<br>
<br>
We can never rewrite basic literals, therefore we can say that they<br>
have constant value semantics, even if their types are mutable. And<br>
then, it seems that rewriting literal through rvalue reference (==<br>
temporary variable) is counter-intuitive, and less useful.<br>
On the other hand, compound literals usually have mutable<br>
elements/fields, so called function may use and rewrite them. It is<br>
often useful.<br>
<br>
More details of my proposal with an actual code:<br>
<br>
struct S{}<br>
<br>
void foo(const ref int v){}<br>
void foo(const ref double v){}<br>
void foo(const ref cdouble v){}<br>
void foo(const ref int[] v){}<br>
void foo(const ref int[int] v){}<br>
void foo(const ref S v){}<br>
void bar( ref int v){}<br>
void bar( ref double v){}<br>
void bar( ref cdouble v){}<br>
void bar( ref int[] v){}<br>
void bar( ref int[int] v){}<br>
void bar( ref S v){}<br>
<br>
void hoo(T)(const ref T v){}<br>
void var(T)( ref T v){}<br>
<br>
void main()<br>
{<br>
// cannot bind basic literals to mutable ref<br>
enum int ei = 1024;<br>
foo(1024); static assert(!__traits(compiles, bar(1024)));<br>
hoo(1024); static assert(!__traits(compiles, var(1024)));<br>
foo(ei); static assert(!__traits(compiles, bar(ei)));<br>
hoo(ei); static assert(!__traits(compiles, var(ei)));<br>
<br>
enum double ef = 3.14;<br>
foo(3.14); static assert(!__traits(compiles, bar(3.14)));<br>
hoo(3.14); static assert(!__traits(compiles, var(3.14)));<br>
foo(ef); static assert(!__traits(compiles, bar(ef)));<br>
hoo(ef); static assert(!__traits(compiles, var(ef)));<br>
<br>
enum cdouble ec = 1+1i;<br>
/*foo(1+1i);*/static assert(!__traits(compiles, bar(1+1i)));<br>
/*hoo(1+1i);*/static assert(!__traits(compiles, var(1+1i)));<br>
foo(ec); static assert(!__traits(compiles, bar(ec)));<br>
hoo(ec); static assert(!__traits(compiles, var(ec)));<br>
<br>
// can bind compound literals to mutable ref<br>
enum int[] ea = [1,2];<br>
foo([1,2]); bar([1,2]);<br>
hoo([1,2]); var([1,2]);<br>
foo(ea); bar(ea);<br>
hoo(ea); var(ea);<br>
<br>
enum int[int] eaa = [1:1];<br>
foo([1:1]); bar([1:1]);<br>
hoo([1:1]); var([1:1]);<br>
foo(eaa); bar(eaa);<br>
hoo(eaa); var(eaa);<br>
<br>
enum S es = S();<br>
foo(S()); bar(S());<br>
hoo(S()); var(S());<br>
foo(es); bar(es);<br>
hoo(es); var(es);<br>
}<br>
<br>
Kenji Hara<br>
<br>
2012年4月13日14:58 kenji hara <<a href="mailto:k.hara.pg@gmail.com">k.hara.pg@gmail.com</a>>:<br>
> I think to avoid some useless case, I'd like to add a rule.<br>
><br>
> In basic, literals (e.g. 10, 3.14, "hello") in D are typed as mutable.<br>
> typeof(10) == int<br>
> typeof(3.14) == double<br>
> typeof("hello") == immutable(char)[] // array itself is mutable<br>
><br>
> Then, with new rvalue reference mechanism, literals are assigned to<br>
> mutable temporaries, and be bound to ref.<br>
><br>
> void foo(ref int n){}<br>
> foo(10);<br>
> // same as int tmp = 10; foo(tmp);<br>
><br>
> But it is less useful behavior.<br>
><br>
> I propose that if rvalue reference binding is needed, and the rvalue<br>
> is built-in literal, its type is treated as const.<br>
><br>
> void foo(ref int n){}<br>
> foo(10);<br>
> // same as const(int) tmp = 10; foo(tmp);<br>
> // tmp is const, and binding const variable to mutable ref is illegal,<br>
> then raises an error.<br>
><br>
> Finally, I don't know we should apply this rule to struct literal too.<br>
> It sounds good, but I afraid that is too restrict.<br>
><br>
> Kenji Hara<br>
><br>
> 2012年4月11日13:33 Andrei Alexandrescu <<a href="mailto:andrei@erdani.com">andrei@erdani.com</a>>:<br>
>> On 4/10/12 7:57 PM, Walter Bright wrote:<br>
>>><br>
>>> 2.<br>
>>> double& d;<br>
>>> int i;<br>
>>> void foo() {<br>
>>> d = i;<br>
>>> }<br>
>><br>
>><br>
>> This example is off; a reference can't be rebound. The relevant example is:<br>
>><br>
>> void increment(double& d)<br>
>> {<br>
>> ++d;<br>
>> }<br>
>> ...<br>
>> int i;<br>
>> increment(i);<br>
>><br>
>> People think the int has been incremented, but in fact a useless temporary<br>
>> has.<br>
>><br>
>> The discussion about what to do in D has been a bit longer and more<br>
>> far-reaching than Walter mentioned.<br>
>><br>
>> The long-term plan is to never let the address of a ref escape the<br>
>> expression in which the ref occurs. That means in essence that user code<br>
>> can't take the address of a ref.<br>
>><br>
>> Once that is in place, we will know for sure that all ref passed into and<br>
>> returned by functions will not escape the immediate expression in which that<br>
>> happens - great for safe code.<br>
>><br>
>> People who need to take &this and escape it (e.g in linked lists implemented<br>
>> with struct) will not be able to; they'll have to use static functions and<br>
>> pointers for that. Generally any work that involves escaping pointers will<br>
>> have to use pointers, not references.<br>
>><br>
>> I think this puts us in a very good spot:<br>
>><br>
>> 1. Safe code will be able to use ref liberally<br>
>><br>
>> 2. Functions will be able to return ref knowing the ref won't survive the<br>
>> current expression. This is awesome for sealed containers - safe and fast.<br>
>><br>
>> What does this have to do with rvalues and lvalues? It means that with the<br>
>> appropriate precautions, we _can_ transform rvalues into lvalues, because we<br>
>> know their address can't unsafely escape.<br>
>><br>
>> There is one precautions to take: we should never convert a value of type T<br>
>> to a ref of another type U. That would cause the problems we learned from<br>
>> C++. There are 3 cases of such implicit conversions:<br>
>><br>
>> 1. built-in numerics, e.g. an int should not convert to a ref double.<br>
>><br>
>> 2. Class inheritance, e.g. a Widget should not convert to a ref Object.<br>
>><br>
>> 3. alias this, e.g.:<br>
>><br>
>> struct T {}<br>
>> struct A { @property T fun(); alias fun this; }<br>
>> void fun(ref T);<br>
>> ...<br>
>> A a;<br>
>> fun(a); // should not work<br>
>><br>
>><br>
>> I think this all holds water. Destroy!<br>
>><br>
>> Andrei<br>
>><br>
>><br>
>> _______________________________________________<br>
>> dmd-beta mailing list<br>
>> <a href="mailto:dmd-beta@puremagic.com">dmd-beta@puremagic.com</a><br>
>> <a href="http://lists.puremagic.com/mailman/listinfo/dmd-beta" target="_blank">http://lists.puremagic.com/mailman/listinfo/dmd-beta</a><br>
</blockquote></div>