## digitalmars.D.learn - Operator Overloading with multiple return types

- eXodiquas (23/23) Mar 15 Hi everyone,
- Sebastiaan Koppe (4/5) Mar 15 Yep. Just make the return type in the function declaration
- =?UTF-8?Q?Ali_=c3=87ehreli?= (13/18) Mar 15 Or use template constraints:
- eXodiquas (20/39) Mar 15 Thanks for the quick and simple answers, but I don't get this
- drug (16/64) Mar 15 You add wrong braces (`if` here is part of method signature not its body...
- H. S. Teoh (21/59) Mar 15 [...]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (10/53) Mar 15 My editor did that. :)
- H. S. Teoh (26/38) Mar 15 This is why I don't trust auto-formatters. ;-)
- H. S. Teoh (18/29) Mar 15 [...]

Hi everyone, i'm currently working on a small physics engine and I thought it would be a nice feature to overload the operators of my vector struct so I don't have to make ugly function calls just to add and "multiply" my vectors. The problem now is that overloading the addition and subtraction of my vector struct is straight forward because both return and take a vector, dot product is not working for me because it is not possible to overload a function by return type (at least not that I am aware of). My code looks like the one from the dlang docs: Vector opBinary(string op)(Vector rhs) { static if (op == "+") return Vector(this.x + rhs.x, this.y + rhs.y); else static if (op == "-") return Vector(this.x - rhs.x, this.y - rhs.y); } As you can see for the dot product the return type has to be a float/double and not a vector. Is there any way to achive this behaivour with D2? The opMul() function is not D2 style and I don't want to use it. Thank you very much, eXodiquas

Mar 15

On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:Is there any way to achive this behaivour with D2?Yep. Just make the return type in the function declaration `auto`. You are then free to return a different type in each static branch.

Mar 15

On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:On Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:Or use template constraints: struct Vector { Vector opBinary(string op)(Vector rhs) if (op == "+") { return Vector(); } double opBinary(string op)(Vector rhs) if (op == "/") { return 0.5; } } AliIs there any way to achive this behaivour with D2?Yep. Just make the return type in the function declaration `auto`. You are then free to return a different type in each static branch.

Mar 15

On Friday, 15 March 2019 at 21:46:50 UTC, Ali Ã‡ehreli wrote:On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:Thanks for the quick and simple answers, but I don't get this one. If I do it that way the compiler doesn't know which function to call, or am I doing something wrong? Vector2 opBinary(string op)(Vector2 rhs) { if (op == "+") { return Vector2(this.x + rhs.x, this.y + rhs.y); } else if (op == "-") { return Vector2(this.x - rhs.x, this.y - rhs.y); } } float opBinary(string op)(Vector2 rhs) { if (op == "*") { return this.x * rhs.x + this.y * rhs.y; } } This gives me the error: overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for opBinary eXodiquasOn Friday, 15 March 2019 at 21:35:12 UTC, eXodiquas wrote:Or use template constraints: struct Vector { Vector opBinary(string op)(Vector rhs) if (op == "+") { return Vector(); } double opBinary(string op)(Vector rhs) if (op == "/") { return 0.5; } } AliIs there any way to achive this behaivour with D2?Yep. Just make the return type in the function declaration `auto`. You are then free to return a different type in each static branch.

Mar 15

16.03.2019 1:30, eXodiquas Ð¿Ð¸ÑˆÐµÑ‚:On Friday, 15 March 2019 at 21:46:50 UTC, Ali Ã‡ehreli wrote:You add wrong braces (`if` here is part of method signature not its body): ``` Vector2 opBinary(string op)(Vector2 rhs) if (op == "+") { return Vector2(this.x + rhs.x, this.y + rhs.y); } Vector2 opBinary(string op)(Vector2 rhs) if (op == "-") { return Vector2(this.x - rhs.x, this.y - rhs.y); } float opBinary(string op)(Vector2 rhs) if (op == "*") { return this.x * rhs.x + this.y * rhs.y; } ```On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:Thanks for the quick and simple answers, but I don't get this one. If I do it that way the compiler doesn't know which function to call, or am I doing something wrong? Vector2 opBinary(string op)(Vector2 rhs) { Â Â Â Â Â Â Â if (op == "+") { Â Â Â Â Â Â Â Â Â Â Â return Vector2(this.x + rhs.x, this.y + rhs.y); Â Â Â Â Â Â Â } else if (op == "-") { Â Â Â Â Â Â Â Â Â Â Â return Vector2(this.x - rhs.x, this.y - rhs.y); Â Â Â Â Â Â Â } Â Â Â } Â Â Â float opBinary(string op)(Vector2 rhs) { Â Â Â Â Â Â Â if (op == "*") { Â Â Â Â Â Â Â Â Â Â Â return this.x * rhs.x + this.y * rhs.y; Â Â Â Â Â Â Â } Â Â Â } This gives me the error: overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for opBinary eXodiquasIs there any way to achive this behaivour with D2?Yep. Just make the return type in the function declaration `auto`. You are then free to return a different type in each static branch.

Mar 15

On Fri, Mar 15, 2019 at 10:30:41PM +0000, eXodiquas via Digitalmars-d-learn wrote:On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:[...][...] Ali's example was unfortunately deceptively formatted. The `if` has to be *outside* the function body; it's not a regular if-statement, but a signature constraint. And there is no `else` clause to it. Vector opBinary(string op)(Vector rhs) if (op == '+' || op == '-') { /* function body begins here */ ... } double opBinary(string op)(Vector rhs) if (op == '*') { /* function body begins here */ ... } T -- Notwithstanding the eloquent discontent that you have just respectfully expressed at length against my verbal capabilities, I am afraid that I must unfortunately bring it to your attention that I am, in fact, NOT verbose.Or use template constraints: struct Vector { Vector opBinary(string op)(Vector rhs) if (op == "+") { return Vector(); } double opBinary(string op)(Vector rhs) if (op == "/") { return 0.5; } } AliThanks for the quick and simple answers, but I don't get this one. If I do it that way the compiler doesn't know which function to call, or am I doing something wrong? Vector2 opBinary(string op)(Vector2 rhs) { if (op == "+") { return Vector2(this.x + rhs.x, this.y + rhs.y); } else if (op == "-") { return Vector2(this.x - rhs.x, this.y - rhs.y); } } float opBinary(string op)(Vector2 rhs) { if (op == "*") { return this.x * rhs.x + this.y * rhs.y; } } This gives me the error: overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for opBinary

Mar 15

On 03/15/2019 03:48 PM, H. S. Teoh wrote:On Fri, Mar 15, 2019 at 10:30:41PM +0000, eXodiquas via Digitalmars-d-learn wrote:My editor did that. :) On my work computer, I've been experimenting with pulling the 'if', 'in', etc to the same level as the function signature: int foo(T)(T t) if (isBlah!T) in (!t.empty) { // ... } AliOn Friday, 15 March 2019 at 21:46:50 UTC, Ali Ã‡ehreli wrote:[...][...] Ali's example was unfortunately deceptively formatted.Or use template constraints: struct Vector { Vector opBinary(string op)(Vector rhs) if (op == "+") { return Vector(); } double opBinary(string op)(Vector rhs) if (op == "/") { return 0.5; } } AliThanks for the quick and simple answers, but I don't get this one. If I do it that way the compiler doesn't know which function to call, or am I doing something wrong? Vector2 opBinary(string op)(Vector2 rhs) { if (op == "+") { return Vector2(this.x + rhs.x, this.y + rhs.y); } else if (op == "-") { return Vector2(this.x - rhs.x, this.y - rhs.y); } } float opBinary(string op)(Vector2 rhs) { if (op == "*") { return this.x * rhs.x + this.y * rhs.y; } } This gives me the error: overloads (Vector2 rhs) and (Vector2 rhs) both match argument list for opBinary

Mar 15

On Fri, Mar 15, 2019 at 04:29:22PM -0700, Ali Çehreli via Digitalmars-d-learn wrote:On 03/15/2019 03:48 PM, H. S. Teoh wrote:[...]This is why I don't trust auto-formatters. ;-)Ali's example was unfortunately deceptively formatted.My editor did that. :)On my work computer, I've been experimenting with pulling the 'if', 'in', etc to the same level as the function signature: int foo(T)(T t) if (isBlah!T) in (!t.empty) { // ... }[...] Phobos style also dictates that: int foo(T)(T t) if (isBlah!T) in (!t.empty) { ... } In my own code, however, I find it too block-of-text-y, so I prefer to indent it inwards: int foo(T)(T t) if (isBlah!T) in (!t.empty) { ... } But if your style puts { at the end of the line rather than the beginning, this could make it even easier to confuse for a statement inside the body. So YMMV. T -- IBM = I'll Buy Microsoft!

Mar 15

On Fri, Mar 15, 2019 at 09:35:12PM +0000, eXodiquas via Digitalmars-d-learn wrote: [...]Vector opBinary(string op)(Vector rhs) { static if (op == "+") return Vector(this.x + rhs.x, this.y + rhs.y); else static if (op == "-") return Vector(this.x - rhs.x, this.y - rhs.y); } As you can see for the dot product the return type has to be a float/double and not a vector. Is there any way to achive this behaivour with D2? The opMul() function is not D2 style and I don't want to use it.[...] Use signature constraints to declare different overloads depending on what the operator is. For example: Vector opBinary(string op)(Vector rhs) if (op == "+" || op == "=") { ... /* implement + and - here */ } double opBinary(string op)(Vector rhs) if (op == "*") { ... /* implement dot product here */ } T -- It is widely believed that reinventing the wheel is a waste of time; but I disagree: without wheel reinventers, we would be still be stuck with wooden horse-cart wheels.

Mar 15