Thread overview
Calling function explicitly from mixin template results in recursive call instead
Dec 09, 2018
Dennis
Dec 10, 2018
Dennis
Dec 10, 2018
aliak
Dec 10, 2018
Dennis
December 09, 2018
I'm using Adam's workaround from https://issues.dlang.org/show_bug.cgi?id=19365, but now I have endless recursion. Reduced code:

```
mixin template operators() {
    S opBinary(string op: "+")(S rhs) {
        return rhs;
    }

    // (A)
    auto opBinary(string op, T)(T rhs) if (false) {
        return rhs;
    }
}

struct S {
    mixin operators ops;
    S opBinary(string op, T)(T a) {
        return ops.opBinary!op(a);
    }
}

void main() {
    S.init.opBinary!"+"(S.init);
}
```

Believe it or not, `ops.opBinary!op(a);` doesn't call anything from the mixin template ops, but it calls itself and it results in a stack overflow. I think this is a bug, but last time I was wrong, so maybe someone can explain what's going on here.

Note that after removing the opBinary at (A), it works. The idea behind it is that it converts the rhs to an S that opBinary!"+" takes. A less reduced version would be:

```
auto opBinary(string op, T)(T rhs) if (!is(T==S)) {
    return this.opBinary!op(S(rhs));
}
```

Does anyone know how to get this working?
December 10, 2018
On Sunday, 9 December 2018 at 18:36:50 UTC, Dennis wrote:
> Does anyone know how to get this working?

I added this to the mixin template:
```
alias mixinOpBinary = opBinary;
```

And called mixinOpBinary instead in the forwarded function. I think that solved it. I think I'll just file an issue for this.
December 10, 2018
On Sunday, 9 December 2018 at 18:36:50 UTC, Dennis wrote:
> I'm using Adam's workaround from https://issues.dlang.org/show_bug.cgi?id=19365, but now I have endless recursion. Reduced code:
>
> ```
> mixin template operators() {
>     S opBinary(string op: "+")(S rhs) {
>         return rhs;
>     }
>
>     // (A)
>     auto opBinary(string op, T)(T rhs) if (false) {
>         return rhs;
>     }
> }
>
> struct S {
>     mixin operators ops;
>     S opBinary(string op, T)(T a) {
>         return ops.opBinary!op(a);
>     }
> }
>
> void main() {
>     S.init.opBinary!"+"(S.init);
> }
> ```
>
> Believe it or not, `ops.opBinary!op(a);` doesn't call anything from the mixin template ops, but it calls itself and it results in a stack overflow. I think this is a bug, but last time I was wrong, so maybe someone can explain what's going on here.

I think the docs [0] are not as specific as they can be, but there's this part: "If the name of a declaration in a mixin is the same as a declaration in the surrounding scope, the surrounding declaration overrides the mixin one". Later on there's a section on disambiguating between conflicting symbols, but that sections feels wanting. Furthremore, this seems to work as expected:

mixin template Foo() {
    void f() {
        writeln("Foo.f");
    }
}

mixin Foo foo;
void f() {
    writeln("f");
    foo.f;
}

void main() {
    f;
}

I think I'd file this and see if someone complains.


>
> Does anyone know how to get this working?

Does this fix your issue?

struct S {
    mixin operators ops;
    S opBinary(string op, T)(T a) {
        alias opBinary = ops.opBinary; // explicitly alias opBinary in this scope
        return opBinary!op(a);
    }
}

Cheers,
- Ali

[0] https://dlang.org/spec/template-mixin.html#mixin_scope
December 10, 2018
On Monday, 10 December 2018 at 21:16:23 UTC, aliak wrote:
> Does this fix your issue?
>
> struct S {
>     mixin operators ops;
>     S opBinary(string op, T)(T a) {
>         alias opBinary = ops.opBinary; // explicitly alias opBinary in this scope
>         return opBinary!op(a);
>     }
> }

It does, thanks.

Though I now have problems of the mixin scope not being able to access overloads of the instantiation scope... I'll just stick everything in the template since this is just an uphill battle.