You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Passing rvalues with a reference is unintuitive with preview=rvaluerefparam #22078
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.
structS {
int i;
}
__gshared S gs = S(1);
ref S getRef() => gs;
S getVal() => gs;
intinc(ref S s) =>++s.i;
voidmain()
{
importcore.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.
(This is all with rvaluerefparam enabled.) Maybe a solution is to introduce a third value category lrvalue that is the result of a ternary expression with an lvalue and rvalue branch. It is the same as rvalue for most things, but is an error when passed to a ref parameter or used to initialize a ref variable.
I've looked into this; it's a tough bug to solve, and I'm not 100% sure it should be.
Current behaviour is reasonable.
isLValue for the ternary operator requires both lhs and rhs to be lvalues, but really it should only require one (this will need to be opt-in for arguments).
Function call where it does the rvaluerefparam stuff, doesn't rewrite into the tree like with the ternary operator.
As a former lisp programmer I was personally expecting setf semantics here i.e. each branch keeps its own ref-ness. I'm rewriting NRVO code in this vein to comply with C++ prvalue semantics (too busy to finish them now).
Maybe this should be discussed in the forum before being enabled by default, I guess people from C++ background are OK with the current (argument passing, but not RVO) behavior. I'm quite the opposite, hate this argument passing behavior but OK with ternary breaking RVO (still want to fix RVO though because of C++ interop).
Activity
Bolpat commentedon Nov 26, 2025
(This is all with
rvaluerefparamenabled.) Maybe a solution is to introduce a third value category lrvalue that is the result of a ternary expression with an lvalue and rvalue branch. It is the same as rvalue for most things, but is an error when passed to arefparameter or used to initialize arefvariable.rikkimax commentedon Dec 17, 2025
I've looked into this; it's a tough bug to solve, and I'm not 100% sure it should be.
Current behaviour is reasonable.
limepoutine commentedon Dec 17, 2025
As a former lisp programmer I was personally expecting
setfsemantics here i.e. each branch keeps its own ref-ness. I'm rewriting NRVO code in this vein to comply with C++ prvalue semantics (too busy to finish them now).Maybe this should be discussed in the forum before being enabled by default, I guess people from C++ background are OK with the current (argument passing, but not RVO) behavior. I'm quite the opposite, hate this argument passing behavior but OK with ternary breaking RVO (still want to fix RVO though because of C++ interop).
rikkimax commentedon Dec 17, 2025
In D the way ternary operator works when both true/false branches are by-ref:
*(condition ? &a : &b)What should be happening with the preview switch:
*(condition ? &a : (T temp = b, &temp))limepoutine commentedon Dec 17, 2025
That's right. Dunno if the community thinks the fix's worth the effort.