‹header›
‹date/time›
Click to edit Master text styles
Second level
Third level
Fourth level
Fifth level
‹footer›
‹#›
Several months ago now we had an introduction to design patterns by William Mitchell.
He also started us out with a description of the adapter pattern.
The iterator is another of the 23 patterns described in the gang of four book.
As you can tell from the name, the iterator has a lot to do with iteration, so were going to look at both of those first and perhaps see where iteration could use some improvement.
The iterator design pattern is so useful that lots of language support it in various and differing ways.  I’ve prepared examples in these four languages and we will hopefully be able to step through them in a debugger to see how they work.
Please pay attention, because there is some homework at the end.
So, here we go.
Probably everyone who knows a C-style language will recognize the “for” statement here as an example of iteration.  It has been with us since the 70s or before.  It is used so often that other loops like “while” and “do while” are rare.  If you use BASIC, there you will have “for i=1 to SIZE” and a “next.”
Object-oriented languages, especially C++, have kept this syntax in part for backward compatibility.  Java made an improvement in that arrays are aware of their length, but did not go much beyond that.  In many cases it is easier for the programmer to stick to the procedural recipe than to improve on it.  Let’s see what kinds of potential problems this can cause.
A proposed solution to these problems and others is the iterator.  This is how the gang of four define an iterator: “… a way to access the elements of an aggregate object [collection] sequentially without exposing its underlying representation.”  We will extend this to mean not just an aggregate object, but any aggregate object and also open it up non-sequential access.  There are, for example, iterators that return random elements of a collection.
The first problem that I notice is that this loop really only applies to arrays.  Other data structures have their own idiomatic ways of accessing their members.  If the data structure changes, we can still use the “for” statement, but the details will have to change.
Let’s look at how some of the problematic examples of iteration might look if we used an iterator instead.  Here we have different iterators to traverse different kinds of structures: array, linked list, tree, and queue.  Since they all use the same method, next(), we can define an interface or abstract class and use that for traversal.
In C++ we can override operator++ and use it instead of next() so that we stay compatible with the old procedural code.
If we have to do very many different things with the data structure, then the traversal code is duplicated and this violates the once and only once principle.  In C, this could be avoided using a function pointer and a callback.  For the min and max examples, some sort of state has to be stored as well.  This is somewhat complicated, especially for beginners.
Internal iterators can be used to remove the duplicated traversal code.  We’ll distinguish internal and external iterators shortly.
This is code similar to what we had a few months ago in a demonstration of JUnit and some eXtreme Programming methods, except that code was even more complicated: there was no function “between”.  Instead, there were another six to ten lines of code here.  The code did both the traversal and the processing and therefore violates the single responsibility principle.
Internal iterators can help separate traversal and processing code.  In this example we have an internal iterator which provides tax bracket pairs two at a time so that the tax calculation code need not concern itself with traversal.
Here is an example of a problem that I used to try to solve in BASIC.  It is a brute force solution of the equation “hocus + pocus = presto”.  On old computers this would take several days to solve and there was no way to exit this program and continue it later because there is no good way to jump into the middle of it.  The state is contained in transient variables. 
In this example, the state of the search is encapsulated in this variable hocusPocusPrestoOdometer, which can be copied, stored, reset, and so on.  It is a bookmark in the list of possible values for h, o, c, u, and s.
Here are some of the design goals according to the Design Patterns book.  The first three we sort of talked about already.
An example of the fourth is if we want to go either forward or backward through a collection.
We might also want to keep track of two cursors simultaneously.
While doing this, we don’t want to compilcate the interfaces of collections.  For example, we don’t want to have to add push() and pop() to strings so that they can act as queues, and prev() and next() so they can act like linked lists, and so on.
Here is a simple, somewhat more concrete example taken from Design Patterns.  For the List class there is an iterator class called ListIterator, which knows about its list.  It keeps track of an index, which gives the current position in the list.  It returns the element at that index upon request and it knows when all elements have been processed.  The interface is adequate for writing the loop.  This is an external iterator because the client code controls the traversal with iterator.Next().
With an internal iterator, the client code does not control the iteration.  Here something unseen is calling Next() and CurrentItem(), but we’ll see shortly that C# really uses an external iterator behind the scenes.
Here are a few issues that you can think about as we look at some concrete examples.  For the most part, these issues all have relatively good solutions.
My conclusion here isn’t very bold.  These four languages support iterators either through syntax or libraries and it’s not as complicated as one might think.  The standard OO adoption process is effective.  Use what’s there to get started, then begin making your own, and finally move away from the procedural version, iteration, and toward the object-oriented solution, iterators instead.
Here is an example program found in a published book that desperately needs some iterators.  If you ever wonder why your computer is so slow, you might guess that it is trying to divide every single number nearly twice by both five and seven.  I’d like to see who can come up with a better way and maybe we can offer a prize for the best solution.