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

Reply via email to