Ayende @ Rahien

It's a girl

Design patterns in the test of time: Iterator

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

More about this pattern.

It is really hard to think about any other pattern that has been more successful. In particular, patterns have long been about overcoming shortcoming of the language or platform.

In this case, iterators has became part of both language and platform in most modern systems.

  • System.Collection.IEnumerable
  • java.util.Iterator
  • Python’s __iter__()

Basically, it is so good, it is everywhere.

Comments

Ryan Heath
01/18/2013 12:26 PM by
Ryan Heath

Ah, remembering those days when I first met them, C++ STL anyone? ;)

// Ryan

Sergey Shumov
01/18/2013 02:30 PM by
Sergey Shumov

Ayende, what do you think about to write a couple of posts on how things are organized in Hibernating Rhinos? It would be interesting to read about your CI process, development workflow, internal rules, priorities management, etc...

kindof
01/20/2013 01:59 PM by
kindof

Ayende, did you know that Scott Hanselman and Rob Conery make jokes of your voice at the end of Hanselminutes 353? :D

Ayende Rahien
01/21/2013 08:15 AM by
Ayende Rahien

Sergey, Sure, do you have any specific questions?

Frisian
01/28/2013 10:04 AM by
Frisian

The Iterator pattern may be omnipresent, but IMHO that doesn't say anything about its current value: - The abstraction level of the pattern is too low: In order to work, the pattern forces you to place a loop into your code. It's a code smell in my book, if someone else's code dictates the control structures in my code. Iterating over a collection can be abstracted away in a forEach() method, that takes a callback handler, which in turn is invoked for every element of the collection. Every SAX parser works like this. - Because of the low abstraction level the Iterator pattern effectively prohibits parallel execution of a piece of code. Nowadays, that is almost bad in itself. With a dedicated forEach() method on the other hand, that's rather simple: Mark the callback handler as side-effect-free by flag, annotation or marker interface and the iteration can be parallelized. By comparison, every SQL statement is written in a way that allows the database to execute it in parallel. - An iterator is stateful and mutable. Passing around an iterator as an argument leads to complex coupling of the affected code. Refactoring such code will be arduous at best.

Ayende Rahien
01/28/2013 11:03 AM by
Ayende Rahien

Frisian, Where on earth did you get the idea that iterator forbid parallel execution. See Parallel.For and Parallel.ForEach as good counter examples. Sure, iterator is low level, but most design patterns are.

Frisian
01/28/2013 01:24 PM by
Frisian

I am not a C# programmer, but what I could take from an example for Parallel.ForEach (http://msdn.microsoft.com/en-us/library/dd460720.aspx) seems to prove my point: it's a method with a callback, that is presented one element at a time. And that is definitely not the GoF-Iterator, for which you provided the Wikipedia link in your article. Interestingly, both "standard" implementations (IEnumerator in C#, Iterator in Java) share a common problem: they are mixing command and query. Iterator.next() not only returns the current element, but also advances to the next one. IEnumerator.MoveNext() moves to the next element and tells, if there is a next element at all. Likewise, they both don't adhere to "Tell, don't ask", thus promoting coupling. Lastly, I wasn't complaining about the abstraction level being "low", but being "too low". The loop really doesn't belong on the caller's side.

Ayende Rahien
01/28/2013 01:36 PM by
Ayende Rahien

Frisian, Next / MoveNext does NOT do two things. It tries to move to the next one, returning true if it succeeded. The return value is if the next operation was successful, not if the future next operation will be. And Parallel.ForEach works using an iterator.

Comments have been closed on this topic.