www.digitalmars.com         C & C++   DMDScript  

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

reply eXodiquas <exodiquas gmail.com> writes:
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
next sibling parent reply Sebastiaan Koppe <mail skoppe.eu> writes:
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
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:
 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.
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; } } Ali
Mar 15
parent reply eXodiquas <exodiquas gmail.com> writes:
On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:
 On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:
 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.
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; } } Ali
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 eXodiquas
Mar 15
next sibling parent drug <drug2004 bk.ru> writes:
16.03.2019 1:30, eXodiquas пишет:
 On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli wrote:
 On 03/15/2019 02:43 PM, Sebastiaan Koppe wrote:
 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.
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;     } } Ali
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 eXodiquas
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; } ```
Mar 15
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
[...]
 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;
     }
 }
 
 Ali
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
[...] 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.
Mar 15
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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:
 On Friday, 15 March 2019 at 21:46:50 UTC, Ali Çehreli 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;
      }
 }

 Ali
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
[...] 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) { // ... } Ali
Mar 15
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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:
[...]
 Ali's example was unfortunately deceptively formatted.
My editor did that. :)
This is why I don't trust auto-formatters. ;-)
 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
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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