Arrayzing Design Choices

Lately, I’ve been working an awful lot on a new project called Arrayzing.  The goal of Arrayzing is to adapt the design of jQuery to work with JavaScript arrays of anything. 

For example, to get all the numbers out of an Arrayzing array (which I have started calling a zing, much to Kevin’s dismay) we would simply have to do this:

_(1, 2, "foo", function() { return 42 }, false, 3, 42).numbers();

Although this is useful in itself, Arrayzing can still do more. Imagine that not only did we want to extract all the numbers in an array, we wanted to sum them too. Arrayzing can handle that without breaking a sweat:

_(1, 2, "foo", function() {}, false, 3, 42).numbers().sum();

And that’s just scratching the surface! But enough about that (we’ll deal with the power of Arrayzing is many posts in the future). Let’s talk about API design.

Arrayzing has been a lot of fun to design. Along the way there have been many design decisions to make and I thought it’d be useful to write about them for the benefit of myself and other would-be API designers.

The first decision I’ll talk about is probably the most radical of the recent changes. It has to do with the functional nature of Arrayzing (which was inherited from jQuery).

Basically, every time an Arrayzing command causes a zing to change (i.e. the numbers() function is invoked), Arrayzing will return a new zing as opposed to just returning a modified version of the current zing. (Remember, a zing is an Arrayzing object). This idea is illustrated below:

// str() is just a convenient way of calling toString()
var a = _(1, "two", 3);
a.str(); // "1,two,3"
var b = a.numbers();
a.str(); // "1,two,3"
b.str(); // "1,3"

This behaviour can be useful in a number of cases. For instance,

var a = _(1, 2, "three", 4, false, function() {}, "foo");
var sum = a.numbers().sum(); // 7
var strings = a.strings().join(","); // "three,foo"

As you can see, we don’t need to keep a copy of the initial values (1, 2, “three”, etc.), we can simply re-use the initial zing. We also won’t accidentally modify a zing when we don’t want to.

However, sometimes we want to modify an array in-place. For example, imagine we had an object called Reader that would read from some data source, and periodically have strings available. In order to check if the Reader has more strings, we would call Reader.hasNext(). In order to read the next string, we would call Reader.next(). So, to read all the strings that Reader has available at a given moment, we would iterate like this:

var array = new Array();
while (Reader.hasNext())
{
  array.push(Reader.next());
}

That same code in Arrayzing, as I’ve described it so far, would be this:

var zing = _();
while (Reader.hasNext())
{
  zing = zing.push(Reader.next());
}

Which has several problems. First of all, it’s not altogether obvious that this is how we’d it. Secondly, it’s pretty inefficent. Every iteration is creating a new Arrayzing that needn’t exist for our purposes. So what’s the solution? Borrow from our friend Ruby and throw in some mutator methods!

In Ruby, when a method modifies an object in-place, it is suffixed with an exclamation mark !. Unfortunately, JavaScript doesn’t allow for us to use exclamation marks in our variables. In place of that, Arrayzing uses the $ character. So now, in Arrayzing, every function that returns a modified zing also has a sister function with a suffixed $ that will modify the zing in-place.

Thus, returning to the example with the Reader, we can now use a mutator function:

var zing = _();
while (Reader.hasNext())
{
  zing.push$(Reader.next());
}

1 Comment so far

  1. […] If you’re not familiar with the $ after set$(), check out this article. It means that the function is a […]

Leave a reply

*