Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

What's your preferred way to implement/use vector operations?

  • vec1.dot(vec2)
    • allows to reuse vec1 but is hard to read for longer equations
  • dot(vec1, vec2)
    • A friend of mine prefers this as "dot" isn't a property of vector
  • vec1 * vec2
    • probably looks best, but not possible in all languages (e.g. Java)
share|improve this question
    
What does NumPy library do? –  Job Apr 13 '11 at 16:39
add comment

7 Answers

Overloaded operators can be good, but only if the redefined operators behave similarly to the originals. Since there's two common products for vectors (dot and cross), this can cause problems. (I'd consider operator*() for dot and operator% for cross, but I've never seen that in practice.)

The dot product relates to both vectors equally, so I wouldn't want to use the first version. It looks too much like vec2 applied to vec1 somehow.

Therefore, I'd rather use dot(vec1, vec2). It looks as symmetric as it is, and it doesn't make the vector class interface any bigger. The more stuff you pack into a class (coughstd:stringcough), the more complicated it is, and the more chance of something going wrong somewhere.

share|improve this answer
    
+1 for not overloading to do totally crazy things (though that can be fun). –  TZHX Apr 13 '11 at 14:17
add comment

While this isn't a basis for a good subjective question, I would steer clear of the third example

vec1 * vec2

since multiplication is different from a dot function. This could easily cause confusion from the (subjective intuitive) possibility of overloading the '*' character.

share|improve this answer
2  
It's called a "dot product", so both of them produce "products". That isn't a big problem. The big problem is that there are different products on vectors. 3-D vectors have cross products. Vectors can also have tensor products, but I've never seen that in practice, so it probably isn't important. –  David Thornley Apr 13 '11 at 13:55
    
And it being "the dot product" is exactly why * is a good name for the operator - it mimics the actual proper character used in the mathematical notation. (And so x would be a good operator to use for the cross product (if your language allows it).) –  Frank Shearar Apr 13 '11 at 16:18
add comment

Assuming C++, I would go with your second option.

The last option is my least favourite, but it adds confusion: what does * mean? Dot product or cross product? Particularly if you make vec * scalar scalar multiplication (which I would also avoid, personally) then it becomes even more confusing.

So it's just between the first and second options then. If you read Herb Sutter's article, Monoliths "Unstrung", he goes into great detail about why non-member non-friend functions make a better interface than member functions do, so I won't repeat everything he says, except to say that I agree with much of it.

share|improve this answer
add comment

it depends on the language, for example in haskell you could do soemthing like

v1 `dot` v2

While in Javascript I would probably do something like

v1.dot(v2);

or maybe

Vector.dot(v1, v2);

In lisp/scheme it would be

(dot v1 v2)
share|improve this answer
add comment

In the first example, it looks like you are applying an operation to a vector, but since a vector cannot be converted to a scalar the operation returns a value and does not modify the original object. So maybe dot should be a static method in the Vector class. This gives something similar to the second example:

Vector.dotProduct(v1, v2);
share|improve this answer
add comment

All are valid, it's a matter of taste and the options given by the implementation language.

In a non-functional language, I would probably use the first option. Yes, "dot" isn't strictly a property of the vector, but it can only be applied to vector. In a heavily classed application, having a bunch of global functions lying around can make things tricky, and unless your developers are all well aware of the different functions - they may implement something themself. Having it as a method on the vector object makes it less likely that this will happen.

The second option is the sort of thing I would do if I was working with a functional language. I don't really know how to explain why, but it just looks like it would fit better. Though you could overload the multiply operator, the weak typing in most functional languages would make this awkward I think.

Just my $0.02

share|improve this answer
    
So what symbol would you use for cross-product? –  FrustratedWithFormsDesigner Apr 13 '11 at 13:42
    
I'd still use *, but have it return a vector rather than a double. Overloading is a wonderful thing. –  TZHX Apr 13 '11 at 13:47
    
@TZHX: But... cross-* and dot-* both take two vectors as arguments... how would it know which should return the scalar and which should return the vector? Maybe it's been too long since I did overloaded operators... –  FrustratedWithFormsDesigner Apr 13 '11 at 13:49
    
well, the return type of the function and the variable it's being assigned to... –  TZHX Apr 13 '11 at 13:51
1  
@TZHX: In C++, you can't overload on return type. Trying to have operator*() as both cross and dot products will produce an error. –  David Thornley Apr 13 '11 at 13:53
show 7 more comments

Neither. There already is a perfectly good notation for the dot product of two vectors:

vec1⋅vec2

Why do you want to invent a new one?

Here is a simple example in Haskell:

a ⋅ b = foldl1 (+) $ zipWith (*) a b

infixl 7 ⋅

main = putStrLn $ show $ [1, 3, -5] ⋅ [4, -2, -1]
-- 3

This declares to be a left-associative infix operator at precedence level 7, which is the same associativity, fixity and precedence as Haskell’s other multiplication operators. (Although, generally speaking, the dot product is usually non-associative, so you might want to make it infix 7 instead, to avoid confusion.)

Here is another example in Scala:

sealed case class Vector[T](ns: T*)(implicit n: Numeric[T]) {
  def ⋅(o: Vector[T]) =
    ns zip o.ns map {case (a, b) => n.times(a, b) } reduceLeft (n.plus _)
}

println(Vector(1, 3, -5)⋅Vector(4, -2, -1))
// 3

Unfortunately, Scala doesn’t support user-defined precedence or associativity.

And even in a very restrictive language like Ruby, which unfortunately doesn’t support user-defined operators at all, you can still get a pretty reasonable result by just using a plain old method instead of an operator:

#encoding: UTF-8

class Vector
  def initialize(*ns)
    @ns = ns
  end

  def ⋅ o
    ns.zip(o.ns).map{|a, b| a*b }.reduce(:+)
  end

  protected

  attr_reader :ns
end

def Vector(*ns)
  Vector.new(*ns)
end

puts Vector(1, 3, -5).⋅ Vector(4, -2, -1)
# 3

Or in Clojure:

(defn ⋅ [a b] (reduce + (map * a b)))

(println (⋅ [1 3 -5] [4 -2 -1]))

[Note: the example is obviously very simplistic, since it uses a simple list of numbers for the vector representation. Obviously, in a real vector implementation, you would use a proper Vector type.]

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.