I'm new to OpenTK, and having to multiply the length of a vector I found the Mult()-method. This method is marked obsolete, and a comment refers to the static Multiply()-method. Why is the instance method obsolete?
Posted Sunday, 27 March, 2011 - 19:44 by the Fiddler
Having both instance and static methods would result in ridiculous amounts of code duplication. Static methods are superior because they preserve immutability, so they are way forward. (XNA uses static methods for the same reason).
The static methods create instances of Vector3, they could create them using a copy-constructor all the same, and then call the instance-method to perform the operation, without code duplication.
Why are static methods superior because they preserve immutability? I would not consider implementing the static methods.
Posted Sunday, 27 March, 2011 - 21:23 by the Fiddler
Duplication in that you provide two different ways to perform the same operation. This is not good API design. Besides, the amount of typing for code and documentation involved is way too much for the benefit (just take a look at the source code).
There are actually two operations. A mutable operation where you want to change a vector by multiplying it with a scale, and an immutable operation where you want to get a new vector being the result of multiplying a vector with a scale.
Currently Vector3 has three implementations of this: one mutable (the instance-method, marked obsolete), and two immutable (the static method and the operator *).
I will suggest that the obsolete-remark is removed from the instance method, and placed on the static method, making it refer to the operator *. The static method is procedural and hence obsolete (unless it is really needed) and the operator * makes it redundant. If I want to perform thousands of mutable vector multiplications I don't want the memory manager having to allocate thousands of vectors I don't need, and the only way I can avoid this is by using the obsolete instance method (which I do).
Additionally I will suggest to overload the operator *, to implement the cross product:
publicstaticVector3operator *(Vector3 a, Vector3 b ) ...
Posted Sunday, 27 March, 2011 - 23:00 by the Fiddler
Quote:
The static method is procedural and hence obsolete (unless it is really needed) and the operator * makes it redundant.
Operator * is slower than Vector3.Multiply(ref, ref, out), which is why both are necessary.
Quote:
If I want to perform thousands of mutable vector multiplications I don't want the memory manager having to allocate thousands of vectors I don't need, and the only way I can avoid this is by using the obsolete instance method (which I do).
Vectors, matrices and quaternions are value types, precisely to avoid unnecessary GC pressure. The instance method does not offer any advantage here.
(Insert obligatory comment on premature optimization and the use of profilers).
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
About structs, I very rarely use them, but I see your point on the GC issue.
The instance methods being marked obsolete, and the static methods being refered to as the prefered way of doing things, gives the impression that at the start of OpenTK someone (A) had the idea to make it object-orientered, but then someone (B) came along arguing about efficience. If this is the case, A had the right idea and B really argued against making OpenTK in the first place. If OpenTK is not willing to make the paradigme shift from procedural to object-oriented it makes little sence to make it! I'm NOT saying the procedural paradigme is bad, I'm saying if you want to program within the procedural paradigme choose a procedural language - it's called C not C#.
Posted Monday, 28 March, 2011 - 17:38 by the Fiddler
fkj wrote:
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
Operator * pushes its arguments to the stack and copies the result back, exactly like staticVector3 Multiply(Vector3, Vector3). The ref overload passes its parameters in registers, which brings a measurable performance improvement.
On the other hand, operators are much cleaner to use, which is why both are available (this is what most/all .net math libraries do).
Quote:
The instance methods being marked obsolete, and the static methods being refered to as the prefered way of doing things, gives the impression that at the start of OpenTK someone (A) had the idea to make it object-orientered, but then someone (B) came along arguing about efficience. If this is the case, A had the right idea and B really argued against making OpenTK in the first place. If OpenTK is not willing to make the paradigme shift from procedural to object-oriented it makes little sence to make it! I'm NOT saying the procedural paradigme is bad, I'm saying if you want to program within the procedural paradigme choose a procedural language - it's called C not C#.
Initially, we had both instance and static methods. This soon became a maintenance burden so we decided to drop half of them. XNA came out around that time and it used static methods - we decided to do the same. (This is ancient history).
Also note that OpenTK.Graphics.OpenGL is 100% procedural, so it's not as if OpenTK is some bastion of OO. :)
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
Operator * pushes its arguments to the stack and copies the result back, exactly like staticVector3 Multiply(Vector3, Vector3). The ref overload passes its parameters in registers, which brings a measurable performance improvement.
Really? Which register would that be?
Did you actually try to measure it? I found no significant differences (edit actually by value wins) - which makes me think its optimised to the same code.
Use of the stack and simple memory copies tend to be very fast because reference fetches are not as cachable.
You'd typically only want to pass by value for larger objects than 3d vectors.
Comments
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
Having both instance and static methods would result in ridiculous amounts of code duplication. Static methods are superior because they preserve immutability, so they are way forward. (XNA uses static methods for the same reason).
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
The static methods create instances of Vector3, they could create them using a copy-constructor all the same, and then call the instance-method to perform the operation, without code duplication.
Why are static methods superior because they preserve immutability? I would not consider implementing the static methods.
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
Duplication in that you provide two different ways to perform the same operation. This is not good API design. Besides, the amount of typing for code and documentation involved is way too much for the benefit (just take a look at the source code).
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
There are actually two operations. A mutable operation where you want to change a vector by multiplying it with a scale, and an immutable operation where you want to get a new vector being the result of multiplying a vector with a scale.
Currently Vector3 has three implementations of this: one mutable (the instance-method, marked obsolete), and two immutable (the static method and the operator *).
I will suggest that the obsolete-remark is removed from the instance method, and placed on the static method, making it refer to the operator *. The static method is procedural and hence obsolete (unless it is really needed) and the operator * makes it redundant. If I want to perform thousands of mutable vector multiplications I don't want the memory manager having to allocate thousands of vectors I don't need, and the only way I can avoid this is by using the obsolete instance method (which I do).
Additionally I will suggest to overload the operator *, to implement the cross product:
public static Vector3 operator *( Vector3 a, Vector3 b ) ...Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
The static method is procedural and hence obsolete (unless it is really needed) and the operator * makes it redundant.
Operator * is slower than
Vector3.Multiply(ref, ref, out), which is why both are necessary.If I want to perform thousands of mutable vector multiplications I don't want the memory manager having to allocate thousands of vectors I don't need, and the only way I can avoid this is by using the obsolete instance method (which I do).
Vectors, matrices and quaternions are value types, precisely to avoid unnecessary GC pressure. The instance method does not offer any advantage here.
(Insert obligatory comment on premature optimization and the use of profilers).
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
About structs, I very rarely use them, but I see your point on the GC issue.
The instance methods being marked obsolete, and the static methods being refered to as the prefered way of doing things, gives the impression that at the start of OpenTK someone (A) had the idea to make it object-orientered, but then someone (B) came along arguing about efficience. If this is the case, A had the right idea and B really argued against making OpenTK in the first place. If OpenTK is not willing to make the paradigme shift from procedural to object-oriented it makes little sence to make it! I'm NOT saying the procedural paradigme is bad, I'm saying if you want to program within the procedural paradigme choose a procedural language - it's called C not C#.
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
Operator * pushes its arguments to the stack and copies the result back, exactly like
static Vector3 Multiply(Vector3, Vector3). The ref overload passes its parameters in registers, which brings a measurable performance improvement.On the other hand, operators are much cleaner to use, which is why both are available (this is what most/all .net math libraries do).
The instance methods being marked obsolete, and the static methods being refered to as the prefered way of doing things, gives the impression that at the start of OpenTK someone (A) had the idea to make it object-orientered, but then someone (B) came along arguing about efficience. If this is the case, A had the right idea and B really argued against making OpenTK in the first place. If OpenTK is not willing to make the paradigme shift from procedural to object-oriented it makes little sence to make it! I'm NOT saying the procedural paradigme is bad, I'm saying if you want to program within the procedural paradigme choose a procedural language - it's called C not C#.
Initially, we had both instance and static methods. This soon became a maintenance burden so we decided to drop half of them. XNA came out around that time and it used static methods - we decided to do the same. (This is ancient history).
Also note that OpenTK.Graphics.OpenGL is 100% procedural, so it's not as if OpenTK is some bastion of OO. :)
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
@Fiddler — Thank you for all your replies :)
Re: Vector3.Mult() - Obsolete - Use static Multiply() ...
If the operator * is slower (why is it slower?), then why are both required? Why not leave the operator * out, using your argument against an API having two ways of doing the same thing, and the maintainability issue?
Operator * pushes its arguments to the stack and copies the result back, exactly like
static Vector3 Multiply(Vector3, Vector3). The ref overload passes its parameters in registers, which brings a measurable performance improvement.Really? Which register would that be?
Did you actually try to measure it? I found no significant differences (edit actually by value wins) - which makes me think its optimised to the same code.
Use of the stack and simple memory copies tend to be very fast because reference fetches are not as cachable.
You'd typically only want to pass by value for larger objects than 3d vectors.
A reference: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/