[dmd-beta] rvalue references

Andrei Alexandrescu andrei at erdani.com
Fri Apr 13 11:40:20 PDT 2012


I'm busy right now, give me some time to look over it.

Thanks,

Andrei

On 4/13/12 1:39 PM, kenji hara wrote:
> How about my idea, Andrei?
>
> Kenji Hara
>
> 2012/04/13 17:47 "kenji hara" <k.hara.pg at gmail.com
> <mailto:k.hara.pg at gmail.com>>:
>
>     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."
>
>     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.
>
>     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)));
>
>     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)));
>
>     // 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);
>     }
>
>     Kenji Hara
>
>     2012年4月13日14:58 kenji hara <k.hara.pg at gmail.com
>     <mailto:k.hara.pg at gmail.com>>:
>      > I think to avoid some useless case, I'd like to add a rule.
>      >
>      > In basic, literals (e.g. 10, 3.14, "hello") in D are typed as
>     mutable.
>      > typeof(10) == int
>      > typeof(3.14) == double
>      > typeof("hello") == immutable(char)[] // array itself is mutable
>      >
>      > Then, with new rvalue reference mechanism, literals are assigned to
>      > mutable temporaries, and be bound to ref.
>      >
>      > void foo(ref int n){}
>      > foo(10);
>      > // same as int tmp = 10; foo(tmp);
>      >
>      > But it is less useful behavior.
>      >
>      > I propose that if rvalue reference binding is needed, and the rvalue
>      > is built-in literal, its type is treated as const.
>      >
>      > void foo(ref int n){}
>      > foo(10);
>      > // same as const(int) tmp = 10; foo(tmp);
>      > // tmp is const, and binding const variable to mutable ref is
>     illegal,
>      > then raises an error.
>      >
>      > Finally, I don't know we should apply this rule to struct literal
>     too.
>      > It sounds good, but I afraid that is too restrict.
>      >
>      > Kenji Hara
>      >
>      > 2012年4月11日13:33 Andrei Alexandrescu <andrei at erdani.com
>     <mailto:andrei at erdani.com>>:
>      >> On 4/10/12 7:57 PM, Walter Bright wrote:
>      >>>
>      >>> 2.
>      >>> double& d;
>      >>> int i;
>      >>> void foo() {
>      >>> d = i;
>      >>> }
>      >>
>      >>
>      >> This example is off; a reference can't be rebound. The relevant
>     example is:
>      >>
>      >> void increment(double& d)
>      >> {
>      >> ++d;
>      >> }
>      >> ...
>      >> int i;
>      >> increment(i);
>      >>
>      >> People think the int has been incremented, but in fact a useless
>     temporary
>      >> has.
>      >>
>      >> The discussion about what to do in D has been a bit longer and more
>      >> far-reaching than Walter mentioned.
>      >>
>      >> The long-term plan is to never let the address of a ref escape the
>      >> expression in which the ref occurs. That means in essence that
>     user code
>      >> can't take the address of a ref.
>      >>
>      >> Once that is in place, we will know for sure that all ref passed
>     into and
>      >> returned by functions will not escape the immediate expression
>     in which that
>      >> happens - great for safe code.
>      >>
>      >> People who need to take &this and escape it (e.g in linked lists
>     implemented
>      >> with struct) will not be able to; they'll have to use static
>     functions and
>      >> pointers for that. Generally any work that involves escaping
>     pointers will
>      >> have to use pointers, not references.
>      >>
>      >> I think this puts us in a very good spot:
>      >>
>      >> 1. Safe code will be able to use ref liberally
>      >>
>      >> 2. Functions will be able to return ref knowing the ref won't
>     survive the
>      >> current expression. This is awesome for sealed containers - safe
>     and fast.
>      >>
>      >> What does this have to do with rvalues and lvalues? It means
>     that with the
>      >> appropriate precautions, we _can_ transform rvalues into
>     lvalues, because we
>      >> know their address can't unsafely escape.
>      >>
>      >> There is one precautions to take: we should never convert a
>     value of type T
>      >> to a ref of another type U. That would cause the problems we
>     learned from
>      >> C++. There are 3 cases of such implicit conversions:
>      >>
>      >> 1. built-in numerics, e.g. an int should not convert to a ref
>     double.
>      >>
>      >> 2. Class inheritance, e.g. a Widget should not convert to a ref
>     Object.
>      >>
>      >> 3. alias this, e.g.:
>      >>
>      >> struct T {}
>      >> struct A { @property T fun(); alias fun this; }
>      >> void fun(ref T);
>      >> ...
>      >> A a;
>      >> fun(a); // should not work
>      >>
>      >>
>      >> I think this all holds water. Destroy!
>      >>
>      >> Andrei
>      >>
>      >>
>      >> _______________________________________________
>      >> dmd-beta mailing list
>      >> dmd-beta at puremagic.com <mailto:dmd-beta at puremagic.com>
>      >> http://lists.puremagic.com/mailman/listinfo/dmd-beta
>
>
>
> _______________________________________________
> dmd-beta mailing list
> dmd-beta at puremagic.com
> http://lists.puremagic.com/mailman/listinfo/dmd-beta


More information about the dmd-beta mailing list