Cannot use auto ref passing in expression template operator overloads

Nordlöw via Digitalmars-d digitalmars-d at puremagic.com
Wed Jan 18 02:49:43 PST 2017


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


More information about the Digitalmars-d mailing list