I'm currently writing a high-level GMP-wrapper at
https://github.com/nordlow/gmp-d
In order to get efficient scheduling of calls to C API
__gmpz-functions, I want expressions such as
MpZ(3) + MpZ(4)
to return an instance of a lazy expression `MpzAddExpr` if and
only if *both* it's arguments are passed by move to the
`MpzAddExpr`-constructor. This is possible to statically detect
in `auto-ref`-passing *free* functions such as
auto add()(auto ref const MpZ a, auto ref const MpZ b)
{
static if (!isRef!a && !isRef!b) // both r-values
{
// PROBLEM!!!: this case cannot be implemented
// in operator overloads because
// __traits(isRef, this) is incorrectly always true
// safe @nogc and no-RC lazy evaluation is possible
return MpZAddExpr!(MpZ, MpZ)(move(a), move(b));
}
else static if (!isRef!a) // r-value a
{
// `a` is an r-value and can be added in-place as
mpz_add(a._ptr, a._ptr, b._rhs)
return move(a); of type MpZ
}
else static if (!isRef!b) // r-value b
{
// `b` is an r-value and can be added in-place as
mpz_add(b._ptr, b._ptr, a._rhs) // commutative
return move(b); // of type MpZ
}
else // both references
{
// direct evaluation is needed
Z c; // separate allocation needed
mpz_add(c._ptr, a._ptr, b._ptr);
return c; // of type MpZ
}
}
because parameters are passed by D's clever `auto-ref` semantics.
But the same behaviour *cannot* be implemented using operator
overloads for, in this case, `opBinary`-plus.
The problem boils down to the fact that
__traits(isRef, this)
in members such as
struct S
{
opUnary(string)() if (s == "-")
{
pragma(msg, __traits(isRef, this));
}
}
evaluates to true in expressions such as
-(S.init)
eventhough `S` here clearly is an r-value.
This blocks the library from applying nice optimizations during
the evaluation of these lazily-evaluted expressions if operator
oveloading is to be used.
I expected this to be fixed by qualifying the member as `auto ref`
opUnary(string)() auto ref if (s == "-")
but that errors.
Is this by design or by accident?
Is there a way around this problem?
For details see
MpZ at https://github.com/nordlow/gmp-d/blob/master/src/gmp.d#L38
MpZAddExpr
https://github.com/nordlow/gmp-d/blob/master/src/gmp.d#L1835