www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Cannot use auto ref passing in expression template operator overloads

reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
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
Jan 18 2017
next sibling parent =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Wednesday, 18 January 2017 at 10:49:43 UTC, Nordlöw wrote:
 https://github.com/nordlow/gmp-d/blob/master/src/gmp.d#L1835
Should be https://github.com/nordlow/gmp-d/blob/master/src/gmp.d#L1853
Jan 18 2017
prev sibling parent Eugene Wissner <belka caraus.de> writes:
On Wednesday, 18 January 2017 at 10:49:43 UTC, Nordlöw wrote:
 Is there a way around this problem?
I had the same problem with opSliceAssign, opIndexAssign lately.
Jan 18 2017