-
-
Notifications
You must be signed in to change notification settings - Fork 664
Description
D's ternary operator (? :) can have reference semantics despite being rvalues. For example, (a() ? a() : b()).mutate() mutates a() if a() returns by reference and happens to be truthy, even if b() returns by value. However, -preview=rvaluerefparam requires implementations to always copy rvalue parameters, allowing the result of function calls to be subtly different from hand-inlined code.
struct S {
int i;
}
__gshared S gs = S(1);
ref S getRef() => gs;
S getVal() => gs;
int inc(ref S s) => ++s.i;
void main()
{
import core.stdc.stdio;
// modifies a copy of gs
inc(getRef().i ? getRef() : getVal());
printf("%d\n", gs.i);
// modifies gs
++((getRef().i ? getRef() : getVal()).i);
printf("%d\n", gs.i);
}In the code above, the inc() call copies its argument and has no side-effect on gs. However, after several versions, the maintainer decides that getVal() should be ref to improve performance. Such a tiny change suddenly changes getRef().i ? getRef() : getVal() into an lvalue, and the code now prints 2 3 instead of 1 2.
The wording in dlang/dlang.org#3924 is not clear about the situation. That all reference semantics is lost when passing an rvalue should be emphasized.