The war between procedural and functional programming continues to rage, and the latest skirmish appears in this article, where the author shows two versions that add the contents of a vector.
Traditional C++
int Dice::total() const { int total = 0; for(const_iterator current = dice.begin(); current != dice.end(); ++current) total += (*current)->faceValue(); return total; }
Functional C++
int Dice::total() const { return std::accumulate( dice.begin(), dice.end(), 0, bind(std::plus(), _1, bind(&Die::faceValue, _2)) ); }
The comments show the usual dichotomy between people who prefer one style over the other (I continue to think the procedural style is vastly more readable), but interestingly, nobody seems to notice the one thing that makes both these snippets terrible examples of clean code: they both use iterators.
Iterators were made popular by the Standard Template Library (STL). When it came out (around 1994 I think), the STL featured a lot of concepts that were quite groundbreaking at the time, such as the extreme emphasis on composition over inheritance, something that is still considered a very good practice today.
Unfortunately, the STL also made iterators very popular, and although back then, iterators definitely raised the level of abstraction in the manipulation of containers and algorithms, their main drawback is that they expose a lot more about the internals of the containers than users really need to know.
When the first versions of the Java Collections came out, they enthusiastically embraced iterators as well. We can’t blame the authors, nobody really knew better back then, and this kind of code:
Old Java
List<Integer> l = ...; int result = 0; for (Iterator<Integer> it = l.iterator(); it.hasNext(); ) { result += it.next(); }
was considered a marvel of abstraction.
It took a few years, but finally, the Java community started wondering why we needed iterators at all for such operations. We have a container, we have elements, and we want to apply a certain operation on these elements. In the description of this problem, iterators are nowhere to be found. This simple realization led to one of the best new features ever introduced in Java : the enhanced for loop.
New Java
List<Integer> l = ...; int result = 0; for (int n : l) { result += n; }
The syntax itself is unimportant (some languages use foreach, others for i in l, etc…), what really matters is that iterators are gone.
Which brings us back to the two code snippets shown at the top of this post. What’s more disturbing is not so much that the procedural version of this code uses iterators (this is, sadly, a common idiom in C++) but that the functional version exposes iterators as well. Why the author of this snippet can even remotely think this is a good idea is beyond me.
And the more I think about iterators, the more I really wonder if they have any place in a public API. At all.
For a while, I thought that being able to traverse a collection without exposing the underlying container sounded like a good idea, so instead of returning a List or a Set, you just return an iterator. I could buy that, although I found that in practice, iterators are pretty hard to manipulate, and as soon as you find yourself needing more sophisticated access to the underlying container (such as the size of the sequence, or random access to its elements), you quickly replace your iterator with a collection exposing the richer interface you need.
Let’s just declare iterators a cute idea that no longer has its place in modern software and move on, shall we?