Which do you prefer?

Started by
8 comments, last by Dawoodoz 11 years, 10 months ago
Hiya,

I've seen all of these 'styles' used for mathematical operations. Could anyone tell me which you prefer, and why?


class Vector3
{
// This?
// Equivalent to a free function.
void normalise();

// Or this?
Vector3& normalise();

// Or this?
Vector3 normalise() const;
}


The first is limiting as you can't use it as part of an equation, but it's unlikely to be confusing. It seems the second and third varieties are more flexible, but could easily be confused, e.g.


// Should v1 be modified here?
Vector3 v1;
Vector3 v2 = v1.normalise();


Which do you use, or which do you prefer? Thanks for any suggestions!
Advertisement
I'd prefer Vector3& normalise(); as it's part of the class, meaning that it actually changes the instance. Also, this returns a reference to the instance itself, so you can use more functions on it in a row.
For your second line, I'd create a global function outside the class, that would return a new instance, without changing the original one:
class Vector3;
Vector3 Normalise(const Vector3&);


This way it makes sense for me, although that global function is still a bit problematic, spamming the global namespace. An alternative could be this:

class Vector3
{
Vector3& Normalise(void); //<- Changing the original instance, then returning itself
Vector3 Normalised(void); //<- Returning a normalised copy of the original one
};

Vector3 v1;
Vector3 v2=v1.Normalised();

Ta-dah!
I actually think a free function is more clear:

Vector3 normalize(Vector3 const &v);

Vector3 v1;
Vector3 v2 = normalize(v1);
I agree with alvaro, free function with the Correct spelling lol. It's how I do all my linear algebra. But at the same time, I am totally obsessed with optimization that even having that extra copy in there urks me sometimes. But i don't do it just because I have an unknown reason against changing a variable passed in a function by reference.

grah you have me thinking about changing all my code lol.
Thanks for that! I think I'm leaning towards free functions too, but then I'd feel I need to make everything a free function for consistency. Some operations sit fine with me as const member functions - the dot product for example, or the determinant of a matrix. So I'll end up with:


float Vector3Dot(const Vector3& v1, const Vector3& v2);
Vector3 Vector3Normalise(const Vector3& v1);

float Matrix3x3Determinant(const Matrix3x3& m);
// etc...


I believe that's how D3DX and it's newer version (XNA Math?) do it. Another alternative is to use free functions which modify the instance passed in rather than return a new one. That way you only pay for a copy if you need it:


void Vector3Normalise(Vector3& v) { /*..*/ }

Vector3 v1;
// Modify the original - no copy.
Vector3Normalise(v1);
// Don't modify the original - copy.
Vector3 v2 = v1;
Vector3Normalise(v2);


Although such copies are unlikely to be a bottleneck.


...free function with the Correct spelling lol.


I'm not even gonna go there tongue.png
I like class functions a lot but they tend to make equations messy in code. Free functions with a return value are much more intuitive in my opinion. For instance to calculate 3x^2 + 2:

Free function with no return value:


square(x);
multiply(x, 3);
add(x, 2);
return x;


Class function:


x.square();
x.multiply(3);
x.add(2);
return x;


Or, if the class function returns itself:

return x.square().multiply(3).add(2);

Free function with return value:

return 3 * x * x + 2; // or return 3x**2 + 2 if ** is supported

Of course this is a trivial example considering the free function is in fact a language operator. Slightly more complicated: calculate normalize(cross(v1, v2)):

Free function with no return value:


cross(v1, v2); // modifies v1
normalize(v1);
return v1;


Class function:


return v1.cross(v2).normalize(); // not bad


Free function with return value:

return normalize(cross(v1, v2));

I don't know about you guys but I prefer the last option. Of course, as always, it depends. All those different methods have they strengths and weaknesses, and sometimes there is no clear "best" option. As for performance, unless you are bottlenecking on arithmetic or memory copy (which is highly unlikely), I wouldn't worry about it.

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

You can always implement both. :-)

I usually prefer class methods but sometimes free functions are more clear. Giving both is not hard and lets the programmer using it decide the most clear version for that particular bit of code. Implement one in terms of the other to save on work, I'd make the class functions first since they don't need temporary values, use them to provide free versions.
Thanks!


I usually prefer class methods but sometimes free functions are more clear.


Do you prefer the functions (whether class methods or free functions) to modify the original?

For me, I think the following would be confusing:


// modifies the original
Vector3& Vector3::cross(const Vector3&);
Vector3& Vector3::normalise();

// uh oh - v1 and v2 have changed!
return v1.cross(v2).normalise();


So I guess I'd prefer all methods to return a copy, but maybe free functions are the most unambigous. Just interested in what everyone thinks.
I generally expect to be able to tell if a function will modify its arguments from the name of the function. If the function is called normalize() I'd expect it to modify the vector so that it's a unit vector. If the function is called something like normalized_vector() I'd expect it to return a normalized copy. I certainly wouldn't expect a function called cross() to modify either of its arguments.
I want all vector arguments to be taken as values so that I can easily see where the variable's last assignment was made.

v = normalize(v);


I prefer vectors to be plain structs so that different math libraries can be combined without too much work.
When integrating a physics engine with a graphics engine, you get 2 types of vectors that have the same data inside but they don't want to work together.
It would be great if all languages would have a standard datatype for vectors and matrices that everyone can use with their own math functions.

This topic is closed to new replies.

Advertisement