Friday, October 10, 2008

ConcurrentModificationException: Why do Java collections not have robust iterators?

Ever got a ConcurrentModificationException? It just hit me. How does this happen? It happens when one method iterates over a collection while another method (that bis recursively called from the for loop) modifies the collection.

Note: ConcurrentModificationException has nothing to do with threading! (Well, this is a bit too strong statement, as Rafael points point out in a comment: it might occur due to a threading race condition (but in such cases you probably have other problems as well)). A ConcurrentModificationException may have nothing to do with threading!. Here I am talking about about the non threading related case.

Here's a simple example to show the problem. We have a class that can register new listeners and when fireChange is called it calls changed on the listeners. So the test listener here removes itself on the change call and boom, we get the ConcurrentModificationException:

public class IteratorTest {
final Collection fListeners;
public IteratorTest(Collection listeners) {
fListeners = listeners;
}
static class Listener {
public void changed(IteratorTest subject) {
subject.removeListener(this);
}
}
public void addListener(Listener listener) {
fListeners.add(listener);
}
public void removeListener(Listener listener) {
fListeners.remove(listener);
}
public void fireChange() {
for (Listener listener : fListeners) {
listener.changed(this);
}
}
static void test(Collection coll) {
IteratorTest t = new IteratorTest(coll);
t.addListener(new Listener());
t.fireChange();
}
public static void main(String[] args) {
test(new ArrayList());
}
}


The problem can happen if you call out to "other code" (code someone else has written) and "other code" can change the collection while you are iterating. One solution is to iterate over a copy of the collection:

public void fireChange() {
Listener[] listeners=(Listener[]) fListeners.toArray();
for (Listener listener : listeners) {
listener.changed(this);
}
}

That helps. But there is a lot of code out there that iterates over a collection and calls "other code" and there is always a chance that the "other code" calls back to modify your collection and you get a ConcurrentModificationException....

The good news is: Unlike threading race conditions it happens deterministically. The bad news is: if you are the client it is often not easy to find a way out.

15 years ago, ET++ (the cool framework created by Erich Gamma and Andree Weinand in the 80ies) suffered form missing robust iterators. "Robust iterators" means robust to changes of the underlying collection. At that time, making a copy of a collection seemed an unacceptable overhead. So, Thomas Kofler added robust iterators to ET++ (the PDF has the pages on reverse order -- here is a readable version). The implementations are efficient and robust.

Robust iterators are so fundamental, I am really surprised that Java does not have them....

.

The bridge between Interaction Design (IxD) and Domain Driven Design (DDD)

Some time ago I read Alan Cooper's book on About Faces 3. I am currently reading his book "The Inmates Are Running the Asylum: Why High Tech Products Drive Us Crazy and How to Restore the Sanity". He makes a strong point that interaction design has to be based on research and that is has to be made by interaction designers and not engineers. Engineers think too technical and therefore will create too complicated solutions. Engineers don't know how "normal users" think. And he is right! But I think, it's not enough to have some "interaction designers" designing the interactions and then let the programmers write the code. That might be important. But it is equally important if not more important that the the developers deeply understands the problems domain and goals the users have.

There is a great one hour talk I really enjoyed: Martin Fowler and Dan North Point Out a Yawning Crevasse of Doom (I had to look up the words Yawning, Crevasse and Doom -- those British guys speak hard to understand English ;-)). Their point is that there has to be a bridge between developers and users in order to communicate as apposed to a ferry, where information is transported from one side to the other by someone like the interaction designer, marketing person or analyst.

The solution requires what Eric Evens describes in his book as Domain Driven Design (DDD) (BTW: Domain Driven Design Quickly is a 100 page book available online describing the essentials). One of the central ideas is to have a dialog between the developers and users to come up with a "ubiquitous language" to describe the "core domain". That is: use the same language when talking to the users as when talking about the code. Create classes and methods that model the domain using the same terminology used by the users when they talk about the problem domain.

To get better software we have apply the techniques of interaction design and we have to have a dialog with our users to be able to create models that match their mind sets.

Yes, I am guilty myself of not doing this. So, this post is a reminder for myself....

P.S.: After writing this post, I did some search on ("DDD and IxD") and I figured that about a year ago I started a discussion on this topic on the IxD mailing list. I wish I would have a better memory....