digitalmars.D.learn - Mixin Templates and Operators
- francesco.andreetto (84/84) Apr 06 2022 I have two structs, point and vec, in which I want to implement
- Tejas (33/117) Apr 06 2022 Looks like a compiler bug, since substituting the real methods
- francesco.andreetto (5/9) Apr 12 2022 Hi Tejas,
- Adam D Ruppe (7/9) Apr 06 2022 mixin templates can't bring in operator overloads. The spec
- Steven Schveighoffer (7/16) Apr 06 2022 As I mentioned elsewhere, it does work. But the situation I think must
- Adam D Ruppe (6/9) Apr 06 2022 ooooooooooh yeah there's multiple here so the names don't
- francesco.andreetto (5/9) Apr 12 2022 Hello Adam D Ruppe,
- francesco.andreetto (6/13) Apr 12 2022 Hello Steve,
- Steven Schveighoffer (30/58) Apr 06 2022 This seems like a bug in the compiler. You can mixin operator overloads
I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that?
Apr 06 2022
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote:I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error: ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` The output of `dub run` is ``` Performing "debug" build using /usr/bin/dmd for x86_64. query ~master: building configuration "application"... source/app.d(27,13): Error: incompatible types for `(p1) - (p2)`: both operands are of type `point` source/app.d(30,15): Error: incompatible types for `(p1) + (v2)`: `point` and `vec` /usr/bin/dmd failed with exit code 1. ``` I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs. If I don't use the mixin templates and, instead, I overload the operations into the structures everything works. ```d struct point{ float x, y, z; vec opBinary(string op)(point rhs) const if (op == "-") { return vec(x - rhs.x, y - rhs.y, z - rhs.z); } point opBinary(string op)(vec rhs) const if (op == "+") { return point(x + rhs.x, y + rhs.y, z + rhs.z); } } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1-p2; vec v2 = {2,-1,0}; point p3 = p1+v2; } ``` Am I doing something wrong or it is impossible to use mixin templates like that?Looks like a compiler bug, since substituting the real methods makes the `mixin template` code compile fine Also, remove the `const`, otherwise the method will word only on `const` instances even if the bug gets fixed ```d mixin template sum(T, R) { R opBinary(string op)(T rhs) const if (op == "+"){ return R(x + rhs.x, y + rhs.y, z + rhs.z); } } mixin template diff(T, R) { R opBinary(string op)(T rhs) const if (op == "-") { return R(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin diff!(point, vec); mixin sum!(vec, point); } struct vec{ float x, y, z; } void main(){ point p1 = {1,2,3}, p2 = {5,6,7}; vec v1 = p1.opBinary!"-"(p2); // made - explicit vec v2 = {2,-1,0}; point p3 = p1.opBinary!"+"(v2); // made + explicit }
Apr 06 2022
On Wednesday, 6 April 2022 at 16:36:51 UTC, Tejas wrote:Looks like a compiler bug, since substituting the real methods makes the `mixin template` code compile fineHi Tejas, Thank you very much for your answer!Also, remove the `const`, otherwise the method will word only on `const` instances even if the bug gets fixedAnd thank you for this advice: I'll definitely remove the `const`! FA
Apr 12 2022
On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote:Am I doing something wrong or it is impossible to use mixin templates like that?mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template.
Apr 06 2022
On 4/6/22 12:52 PM, Adam D Ruppe wrote:On Wednesday, 6 April 2022 at 10:36:04 UTC, francesco.andreetto wrote:As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. Note that I also think string mixins would work perfectly fine. And UFCS will never work for operator overloads, but that is by design. -SteveAm I doing something wrong or it is impossible to use mixin templates like that?mixin templates can't bring in operator overloads. The spec doesn't really say this I think, but that's the way it has been for a long time. It only checks for operator overloads on the direct thing itself, no UFCS, no mixin template.
Apr 06 2022
On Wednesday, 6 April 2022 at 17:33:28 UTC, Steven Schveighoffer wrote:As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself.ooooooooooh yeah there's multiple here so the names don't overload and one on the time itself would override the ones from mixin template. You'd have to alias them together on the type.
Apr 06 2022
On Wednesday, 6 April 2022 at 17:59:12 UTC, Adam D Ruppe wrote:ooooooooooh yeah there's multiple here so the names don't overload and one on the time itself would override the ones from mixin template. You'd have to alias them together on the type.Hello Adam D Ruppe, I see what you mean, thank you very much for your answers! -FA
Apr 12 2022
On Wednesday, 6 April 2022 at 17:33:28 UTC, Steven Schveighoffer wrote:As I mentioned elsewhere, it does work. But the situation I think must be that it's only one mixin template. Probably also you can't have any overloads in the type itself. Note that I also think string mixins would work perfectly fine. And UFCS will never work for operator overloads, but that is by design. -SteveHello Steve, Thank you very much for your answers, you have been very clear and helpful! -FA
Apr 12 2022
On 4/6/22 6:36 AM, francesco.andreetto wrote:I have two structs, point and vec, in which I want to implement some arithmetic operations. The operations are: ``` point - point = vec point + vec = point ``` Using mixin templates the code compiles but calling the operations in the main causes an "incompatible type" Error:This seems like a bug in the compiler. You can mixin operator overloads using one mixin template, but not multiple. e.g. raylib-d uses this: https://github.com/schveiguy/raylib-d/blob/89733bab9fd1d3588c14f4aa54b62ad45022a105/source/raymathext.d#L75I tried to implement a single template: ```d mixin template sumDiff(T, R){ R opBinary(string op)(T rhs) const if (op == "+" || op == "-"){ return mixin("R(x " ~ op ~ " rhs.x, y " ~ op ~ "rhs.y, z " ~ op ~ " rhs.z)"); } } ``` but the same error occurs.This is different from your original. If I do this, it works: ```d mixin template both(T, R) { R opBinary(string op : "+")(T rhs) const { return R(x + rhs.x, y + rhs.y, z + rhs.z); } T opBinary(string op : "-")(R rhs) const { return T(x - rhs.x, y - rhs.y, z - rhs.z); } } struct point{ float x, y, z; mixin both!(vec, point); } ```If I don't use the mixin templates and, instead, I overload the operations into the structures everything works.It also works to call `opBinary` directly: ```d vec v1 = p1.opBinary!"-"(p2); ``` Which leads me to believe it's not an ambiguity error, but rather just a straight omission on how the operator overloading works. I think you should file a bug. -Steve
Apr 06 2022