When to use plain arrays, or, know when you’re repeating yourself

UPDATE: since writing this, Sylvester continues to be tweaked for performance. Some of the below may no longer apply, and you should always do your own testing for performance to find out what works for you. I’m leaving this article up to illustrate the broader points it has to make.

Now that Sylvester allows you to use plain old arrays pretty much anywhere you can use a vector as an argument, how do you decide which one to use? The trick is to know what the the method you’re passing the array/vector to is going to do with it. In the vast majority of cases where vectors are used as arguments, the method is only interested in the vector’s elements. In fact, what often happens is something like this:

someVectorMethod: function(vector) {
  var elements = vector.elements || vector;
  // ...

So elements ends up being an array, whether you pass an array or a vector. You’ll find passing a vector is slightly faster due to the nature of the || operator, and that might lead you to do the following:

// Bad bad code:
var foo = myVector.add($V([2,9,4]));

As well as being ugly, this is really inefficient. You’re calling $V for no reason at all, and the time that takes to run far outweighs the time saving of passing a vector. In this situation,

// Much nicer:
var bar = myVector.add([2,9,4]);

is both cleaner and faster.

It’s only sensible to pass a vector if you’ve already got one in memory as the result of another calculation:

var somePoint = lineA.intersectionWith(PlaneB);

// This is faster...
var foo = myVector.add(somePoint);

// than this...
var bar = myVector.add(somePoint.elements);

For matrices, the reverse is true. Because the Matrix class is written to be able to cope with accepting vectors and matrices as arguments, and to treat vectors as column matrices for multiplication, its methods can’t just use arg.elements || arg to get the necessary array of elements. Matrix arrays are nested, whereas vector ones aren’t. If arg is [9,2,6] (a vector), it must be converted to [[9],[2],[6]] to behave as a column matrix. So, most matrix methods call Matrix.create if they receive a non-matrix argument, and this sorts out the conversion. This means that, if you’ve got a vector you’re going to subject to lots of matrix methods, you’re better off converting it to a matrix beforehand to save all those conversion calls. Even if you’re only calling one matrix method, you’ll find that converting the argument to a matrix before passing it over will save you some time overall. Strange but true.

If you've enjoyed this article, you might enjoy my recently published book JavaScript Testing Recipes. It's full of simple techniques for writing modular, maintainable JavaScript apps in the browser and on the server.