Thread overview
Using multiple mixin templates to implement operator overloading
Dec 12, 2020
Tobias Pankrath
Dec 12, 2020
Paul Backus
Dec 12, 2020
Tobias Pankrath
Dec 12, 2020
Adam D. Ruppe
Dec 12, 2020
Paul Backus
Dec 12, 2020
Dennis
Dec 12, 2020
Adam D. Ruppe
December 12, 2020
I want to wrap e.g. an int and implement basic arithmetic. In the provided example [1] I use  two mixin templates to separately implement scaling (multiplication with int/double) and addition and subtraction with the type itself.

In the end I want to have several distinct wrappers and allow specific operations between them and int / double. It's important that the return values are typed correctly, otherwise I could use std.typecons.Proxy.

My problem is that both overloads of opBinary work, but not at the same time. As soon as I mixin both templates, they stop to work. If I just paste the implementation into the body of WrapInt, they work both at the same time though.

Could someone explain the mechanics behind it?

Thanks!

[1] https://run.dlang.io/is/WbG987


December 12, 2020
On Saturday, 12 December 2020 at 17:36:57 UTC, Tobias Pankrath wrote:
> I want to wrap e.g. an int and implement basic arithmetic. In the provided example [1] I use  two mixin templates to separately implement scaling (multiplication with int/double) and addition and subtraction with the type itself.
>
> In the end I want to have several distinct wrappers and allow specific operations between them and int / double. It's important that the return values are typed correctly, otherwise I could use std.typecons.Proxy.
>
> My problem is that both overloads of opBinary work, but not at the same time. As soon as I mixin both templates, they stop to work. If I just paste the implementation into the body of WrapInt, they work both at the same time though.
>
> Could someone explain the mechanics behind it?
>
> Thanks!
>
> [1] https://run.dlang.io/is/WbG987

Functions from different mixin templates can't overload each other. The reason for this is that, when you mix in a mixin template, it does not *actually* add the declarations inside it to a current scope: instead, it adds them to a new scope, and then (essentially) "imports" them into the current scope.

IMO this is one of the stupider design decisions in D, but it's unlikely it will ever be fixed. The easiest workaround is to use string mixins instead, which work the way you'd expect them to.
December 12, 2020
On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
> Functions from different mixin templates can't overload each other. The reason for this is that, when you mix in a mixin template, it does not *actually* add the declarations inside it to a current scope: instead, it adds them to a new scope, and then (essentially) "imports" them into the current scope.
Much appreciated! Exactly the explanation I needed.


December 12, 2020
On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
> IMO this is one of the stupider design decisions in D, but it's unlikely it will ever be fixed.

It is useful in several other contexts though, including user overriding and private data stores for the mixin.

> The easiest workaround is to use string mixins instead, which work the way you'd expect them to.

But yeah. The other alternative is to alias them together:

class A {
   mixin Whatever a; // need to give it a name here to reference later
   mixin Whatever b;

   // explicitly merge overloads here
   alias opBinary = a.opBinary;
   alias opBinary = b.opBinary;
}


Or you can do a forwarder function yourself but that's getting even more a hassle. Sometimes appropriate though.
December 12, 2020
On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
> IMO this is one of the stupider design decisions in D, but it's unlikely it will ever be fixed. The easiest workaround is to use string mixins instead, which work the way you'd expect them to.

If issue 19365 got fixed, it could be done with an alias instead.
https://issues.dlang.org/show_bug.cgi?id=19365

Currently string mixins are indeed the best option though.
December 12, 2020
On Saturday, 12 December 2020 at 20:26:00 UTC, Dennis wrote:
> If issue 19365 got fixed

eeek I thought that was fixed but apparently not :(

so yeah alias won't work for operator overloads. Does work for other functions so good technique to know but not here.

So for op prolly go with the string mixin....
December 12, 2020
On Saturday, 12 December 2020 at 20:25:48 UTC, Adam D. Ruppe wrote:
> On Saturday, 12 December 2020 at 18:14:31 UTC, Paul Backus wrote:
>> IMO this is one of the stupider design decisions in D, but it's unlikely it will ever be fixed.
>
> It is useful in several other contexts though, including user overriding and private data stores for the mixin.

Sure, but you can always opt in to that behavior by giving the mixin a name. The fact that you can't opt out of it even if you want to is the issue.

It's essentially the same flaw Andrei criticized C++'s `if constexpr` for [1].

[1] https://www.youtube.com/watch?v=tcyb1lpEHm0&t=45m20s