Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Working around operator overloading  (Read 2555 times)

0 Members and 1 Guest are viewing this topic.

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Working around operator overloading
« on: January 21, 2012, 03:53:51 pm »
So let's get this forum rolling. 8)

This question already popped up in the initial JSFML discussion: how will overloaded operators (e.g. for sf::Vector or sf::Color) be represented in JSFML?

I have worked with several Java libraries that attempted to do this, and every single one of them had some kind of ugly flaw to it that made working with it a pain. The approach I personally regard as the "best" is to interpret operators as static functions within the class in question. Unary operators take one parameter, binary operators take two parameters. The returned object is actually a new one, so none of the objects passed is altered in any way.

So, as an example, the + operator for Vector2f would look like this:
Code: [Select]

class Vector2f {

public static Vector2f add(Vector2f a, Vector2f b) {
  return new Vector2f(a.x + b.x, a.y + b.y);
}

[...]

}

An alternative to calling it "add" would be "sum", but personally I see it like functions should be named after what they do, not after what they yield.

Now, assignment operators like += that alter the left operand would be missing. They certainly are very convenient, plus you don't always want the result to be in a new object. I would implement them as object methods like this:
Code: [Select]

class Vector2f {

  public Vector2f add(Vector2f v) {
    this.x += v.x;
    this.y += v.y;
    return this;
  }

}

I am not sure whether it's a problem to name them the same. From the context (object or class), it should be easy enough to differentiate. The += should yield "this" in my opinion, as this allows chain calls such as:
Code: [Select]

Vector2f v = new Vector2f(1, 0).add(u).mul(4).normalize();


So, in conclusion, I consider the following methods for Vector2f:
Code: [Select]

static (returns new object):

static Vector2f add(Vector2f a, Vector2f b); //vector addition
static Vector2f sub(Vector2f a, Vector2f b); //vector subtraction
static Vector2f mul(Vector2f a, float s); //scalar multiplication
static Vector2f mul(Vector2f a, Vector2f b); //scalar (component-wise) multiplication
static float dot(Vector2f a, Vector2f b) //dot product
static Vector2f normal(Vector2f v); //normal of v
static Vector2f neg(Vector2f v); //negated v

object (returns this):

Vector2f add(Vector2f other); //vector addition
Vector2f sub(Vector2f other); //vector subtraction
Vector2f mul(float s); //scalar multiplication
Vector2f mul(Vector2f other); //scalar (component-wise) multiplication
Vector2f normalize(); //normalizes the vector
Vector2f negate(); //negates the vector

Classes such as Color or Time would get their respective versions.
JSFML - The Java binding to SFML.

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Working around operator overloading
« Reply #1 on: January 21, 2012, 07:29:00 pm »
Updated Vector2i, Vector2f, Vector3f, Time and Color with arithmetic operations in the way described. They are subject to change based on what people think. :)
Javadoc: http://jsfml.pdinklag.de/javadoc/
JSFML - The Java binding to SFML.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6197
  • Thor Developer
    • View Profile
    • Bromeon
Working around operator overloading
« Reply #2 on: January 21, 2012, 09:16:28 pm »
The split to static non-altering methods and to non-static altering methods is a very good idea in my opinion. I find it reasonable when the asymmetric expression a.add(b) actually is different from b.add(a).

You forgot division by a scalar, and component-wise division if you also provide the multiplication.

I don't know whether it is clever to call the component-wise operations only mul() and div(), since multiplication/division of vectors is mathematically not defined and thus not intuitive. Something like componentwiseMul() might be clearer, and the longer name should be acceptable regarding the seldom usage.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development: first SFML book

pdinklag

  • Sr. Member
  • ****
  • Posts: 330
  • JSFML Developer
    • View Profile
    • JSFML Website
Working around operator overloading
« Reply #3 on: January 21, 2012, 10:26:47 pm »
Quote from: "Nexus"
I don't know whether it is clever to call the component-wise operations only mul() and div(), since multiplication/division of vectors is mathematically not defined and thus not intuitive. Something like componentwiseMul() might be clearer, and the longer name should be acceptable regarding the seldom usage.

Good idea really. Multiplying (and thus dividing) by a scalar (float) is mathematically defined, so I guess the name for those can be kept short.

Quote from: "Nexus"
You forgot division by a scalar, and component-wise division if you also provide the multiplication.

Well, there's mul(1.0f / ...).  :roll:
Then again, with the same reasoning, you could remove the sub method, so I guess I'll add div as well.
JSFML - The Java binding to SFML.

 

anything