/customers/iconara.net/iconara.net/httpd.www/blog/wp-content/plugins/wp-super-cache/wp-cache-phase1.php Iconara » More on iteration

More on iteration

While iterators (which I covered in my last post) are fantastic, there is more to iteration than that. I’ll cover three common uses for loops and how they can be rewritten in a way that makes your code more reusable and maintainable. Two of the tricks are from the esoteric land of functional programming, and one from Ruby, a cousin of the ActionScript language.

map

Do you often find yourself writing loops that take one data type and transforms it into another? I do it a lot, in ActionScript coding it’s usually lists of XML nodes that I’m turning into proper objects, but it can also be other things, like creating a list of menu items from data objects.

What you do when you do this is mapping (or transforming) from one thing to another, and to do that you need to write some code which is almost always identical. This is a prime candidate for abstraction.

Take this example, in which I want to make a menu of persons, mapping from person objects to menu item objects:

var persons = ...;
var menuItems = new Array();

for ( var i = 0; i < persons.length; i++ ) { var person = persons[i];

var menuItem = new MenuItem();

menuItem.setTitle(person.getName());
menuItem.setAction(...);
menuItem.setEnabled(true);

menuItems.push(menuItem);

}

If you read my last article on iteration you might wonder why I use a for-loop and not iterators. I decided to go with the old way, in order not to have to explain iterators for those who haven’t read the other article (and for those of you who haven’t, I suggest you do).

As you see, out of six or so lines of the loop, three would be more or less exactly the same even if the task was to create a set of whatevers from a set of whatnots. Those are bad, and tedious to write, so let’s get away with them.

If we encapsulate the code that maps from person to menu item and put that in a function we get this code (initialization omitted this time):

for ( var i = 0; i < persons.length; i++ ) {
    var person = persons[i];

var menuItem = mapPersonToMenuItem(person);

menuItems.push(menuItem);

}

Now all we have left is the code which would be the same, regardless of which types we are mapping between, so we can abstract away them.

Remember that in ActionScript you can passa function as argument to another function (this is sometimes referred to as having higer order functions), so we can pass the function that maps from one type to another as argument to a function that takes care of the basics, let’s call that function map:

function map( mappingFunction : Function, fromObjects : Array ) : Array {
    var toObjects = new Array();

for ( var i = 0; i &lt; fromObjects.length; i++ ) {
    toObjects.push(mappingFunction(fromObjects[i]));
}

return toObjects;

}

This is a reusable function for all your mapping needs, giving you cleaner code. Some examples:

var personsToMenuItems = function( person ) {
    var menuItem = new MenuItem();

menuItem.setTitle(person.getName());
menuItem.setAction(...);
menuItem.setEnabled(true);

return menuItem;

}

var menuItems = map(personsToMenuItems, persons);

or from XML nodes to persons:

var personNodesToPersons = ...;

var persons = map(personNodesToPersons, personNodes);

The functions personsToMenuItems and personNodesToPersons are of course trivial to write, they are only the bare minimum code needed to create one type of object from another type, while being completely reusable. We have created two reusable items from a more or less non-reusable piece of loop code, not bad.

Another beauty of map is that it’s, as with most concepts from functional programming, possible to stick multiple calls together, so let’s put the two examples above together to make this beauty:

var menuItems = map(personsToMenuItems, map(personNodesToPersons, personNodes));

In conclusion, you can use map to do away with the boring and duplicated code, and in the process get more reusable code.

filter

Another common use case for loops is filtering objects depending on some criteria. This can also be encapsulated into a filter-function, let’s call it filter.

Instead of this:

var maches = new Array();

for ( var i = 0; i < list.length; i++ ) { if ( list[i].prop == someValue ) { matches.push(list); } }

wouldn’t it be nicer to be able to write something like this:

var myFilter = function( item ) {
    return item.prop == someValue;
}

var matches = filter(myFilter, list);

Now we don’t have to write the loop code over and over again, and we have a reusable filter function for filtering out only the interesting items in our array. You could even create a parametrisable filter function, or a filter function factory, or why not a collection of standard filter functions like equals, isNull, lessThan, greaterThan, and so on.

each

A third common use of loops is simply to do something with each element in a list, calling a couple of methods, performing some calculation on a property, or similar actions that more or less just stack a bunch of method calls on an object.

A really powerful feature of the Ruby language is the each construct, it makes it possible to apply any block of code to each item in a list. Here is an example:

list.each { |item| print item.name + "\n" }

The code print item.name + "\n" is run for each element in the list (which is available in the variable item). It looks kind of familiar, doesn’t it? Kind of like a traditional loop, but without the declarations and other tedious things.

each puts loops on their heads, applying a block of code to each element, instead of giving each element to block of code.

In ActionScript there is no built in way of doing it, but it can be emulated with functions, and that makes it even more powerful, since the functions can also be reused.

var doTheThing = function( item ) {
    item.doSomethingImportant();
}

each(doTheThing, items);

Simpler and nicer than loops, don’t you think?

I’m sure you can figure out a way to implement the each function by now.

Conclusion

I have now showed you three different uses of loops, mapping, filtering and plain using of objects, all rewritten without a single for-loop (ehm, apart from the actual map, filter and each functions, but that doesn’t count), and all more reusable than before.

There are more goodies to find both in functional programming and advanced object oriented languages, but that’s for another article.

2 Responses to “More on iteration”

  1. Andy Baker Says:

    I much prefer the dot syntax to the function version as it’s much more readable and seems to match the way my brain sees the problem (could that be because it’s in subject-verb order like English?)

    You say it can’t be done but it can by injecting methods into the object and array classes. I wasn’t clever enough to actually write the code but this chap was: http://www.rocketboots.com.au/blog/index.cfm?mode=entry&entry=A5C356B1-E081-51EF-A79F47A1601ADEDF (the first article referred to is here: http://www.rocketboots.com.au/blog/index.cfm?mode=entry&entry=A046CDD7-E081-51EF-A7890B1753F05472 )

  2. Theo Says:

    I agree that list.map(fn) is more readable than map(fn, list). Unfortunately the solution presented in the articles you link to rely on adding things to the prototype of library classes, which is not a good idea. It leads to prototype pollution and even less readable code in the larger perspective.

    The problem is that if you don’t know that Array’s prototype has been patched to include map, filter and each you have no idea what’s happening. Moreover, what if two different libraries both patch Array to include a map method, but use different and incompatible implementations? (different parameter order, for example). This is the reason why none of the major Ajax libraries use prototype patching.

    In ActionScript there is also the added problem of when the patches are applied, you have to make sure that they are applied before you try to use the methods they add (by including them in frame 1, for example). Otherwise you will get bugs that are extremely hard to find.

    When I started programming in ActionScript I extended Array, Object and some of the other core classes to include the functionality I needed. But I started noticing that it was harder for me to reuse code that way. I would start a new project, decide that a part of it was very similar to something I had done in another project, include that code, compile and run. And it would not work the way it should. The reason (which is obvious in hindsight, but not there and then) was that the code I had brought over from the other project used my patches, but I had not yet included them in the new project for various reasons. The code would compile fine because to use the patched methods you can’t type your variables, and then you don’t get warnings for non-existent functions. However, when the code runs the methods don’t exist and no runtime errors are raised, the code just continues. This is a really hopeless thing to debug.

    The irony in this is that the reason why JavaScript has prototypes is to support this kind of patching of the core classes. In the end it turned out that for other uses than very simple scripts it wasn’t such a good idea, and more of a problem than a solution.

    The good news is that in ActionScript 3 the Array class includes map, filter and each.

Leave a Reply