Thread overview
mixin template bug with opBinary?
Jul 22, 2022
Anthony Quizon
Jul 22, 2022
Adam D Ruppe
Jul 22, 2022
Anthony Quizon
Jul 22, 2022
Paul Backus
July 22, 2022

Hello,

I'm trying to create a mixin for quick binary operator overloads by passing in types with a corresponding associative array of strings to functions. However,
the code I currently have:

module foo;

mixin template opBi(
    A, A function(A, A)[string] f0,
) {
    static foreach (k, f; f0) { A opBinary(string op: k)(A r) { return f(this, r); } }
}

struct A {
    mixin opBi!(
        A, [ "+": (A a, A b) => a],
    );
}

struct B {
    mixin opBi!(
        B, [ "+": (B a, B b) => a],
    );
}


Will not let me override operators on both struct A and B.

I get:

foo.d(16): Error: mixin `foo.B.opBi!(B, ["+":function (B a, B b) pure nothrow @nogc @safe => a])` does not match template declaration `opBi(A, A function(A, A)[string] f0)`

Is this a bug or am I doing something wrong?

July 22, 2022
On Friday, 22 July 2022 at 12:33:37 UTC, Anthony Quizon wrote:
> Is this a bug or am I doing something wrong?

I think this is a bug. The compiler must not take well to this pattern, maybe the assoc array template argument, but idk. It looks like the first type used gets cached and reused even if it is supposed to change.

I vaguely recall seeing this before.... but yeah smells buggy anyway.


An alternative you might consider is dropping some of the type and using typeof(this):

```
module foo;

mixin template opBi(
    alias f0
) {
    static foreach (k, f; f0) { typeof(this) opBinary(string op:
    k)(typeof(this) r) { return f(this, r); } }
}

struct A {
    mixin opBi!(
        [ "+": (A a, A b) => a],
    );
}

struct B {
    mixin opBi!(
        [ "+": (B a, B b) => a],
    );
}
```

That sidesteps the bug though it just trusts you pass the right type to `f0`.
July 22, 2022

On 7/22/22 8:33 AM, Anthony Quizon wrote:

>

Hello,

I'm trying to create a mixin for quick binary operator overloads by passing in types with a corresponding associative array of strings to functions. However,
the code I currently have:

module foo;

mixin template opBi(
     A, A function(A, A)[string] f0,
) {
     static foreach (k, f; f0) { A opBinary(string op: k)(A r) { return f(this, r); } }
}

struct A {
     mixin opBi!(
         A, [ "+": (A a, A b) => a],
     );
}

struct B {
     mixin opBi!(
         B, [ "+": (B a, B b) => a],
     );
}


Will not let me override operators on both struct A and B.

I get:

foo.d(16): Error: mixin `foo.B.opBi!(B, ["+":function (B a, B b) pure nothrow @nogc @safe => a])` does not match template declaration `opBi(A, A function(A, A)[string] f0)`

Is this a bug or am I doing something wrong?

It's typing the AA differently, and therefore it doesn't fit. The type of the AA you are passing in is T1[string], where it's expecting T2[string], where:

T1 is B function(B, B) pure nothrow @nogc @safe
T2 is B function(B, B)

I don't know if there's a better way to do this, other than use a further template parameter to match the function type passed in.

-Steve

July 22, 2022
On Friday, 22 July 2022 at 12:56:44 UTC, Adam D Ruppe wrote:
> ```
> mixin template opBi(
>     alias f0
> ) {
>     static foreach (k, f; f0) { typeof(this) opBinary(string op:
>     k)(typeof(this) r) { return f(this, r); } }
> }
> ```

Thanks, this seems to do the trick.
July 22, 2022

On Friday, 22 July 2022 at 12:33:37 UTC, Anthony Quizon wrote:

>

I get:

foo.d(16): Error: mixin `foo.B.opBi!(B, ["+":function (B a, B b) pure nothrow @nogc @safe => a])` does not match template declaration `opBi(A, A function(A, A)[string] f0)`

Is this a bug or am I doing something wrong?

Looks like this bug:

https://issues.dlang.org/show_bug.cgi?id=22540