Observers Should Never Throw Exceptions

On ObserversThrowLocalExceptions, WilliamGrosso asked: How do we throw exceptions in an Observer?


The Observer shouldn't throw exceptions. There is no-one to catch them. The protocol could catch and ignore them, but that's dangerous. The Observable doesn't know anything about the Observers - that's the point of the pattern - so is not interested in their failure. -- DaveHarris

Agreed. In CeePlusPlus terms, Observers should provide a Nofail ExceptionGuarantee. -- TimLesher


You need to use a two-phase protocol between the Observable and Observers. In phase one, the Observable proposes the change to the Observables; they can agree to the change or veto it. In the second phase, the Observable updates its state and informs the Observers of the change. This protocol is used in the JavaBeans framework as "veto-able properties" and "bound properties".

-- NatPryce


WilliamGrosso said, (with some paraphrasing): This is related to ObservablesNeedToBeConsistent, because when an observer throws an exception, it flows right through the observable and we wind up with the same problem as on ObservablesNeedToBeConsistent.

The question is: is this entirely theoretical? Have people actually enforced this stricture? Does it not bite us because exceptions rarely happen in an Observable context? And does the need to guarantee this constitute a huge limitation on exceptions?

-- WilliamGrosso


In the Java world, this stricture is habitually enforced by default. That language requires exceptions to be declared by routines which throw them. When you design your Observer protocol, you naturally don't mention exceptions in it and so they cannot be thrown. For example, in the standard library we have:

interface java.util.Observer {
public abstract void update( Observable o, Object arg );
}
Classes conforming to this interface cannot throw exceptions from the update() method. So it's not theoretical, it's standard practice.

(Actually, there are two groups of exception that don't need to be declared. They are for handling bugs and other catastrophic errors. I don't believe this weakens the case.) -- DaveHarris

Those two cases can break a lot of code if not handled properly. If you're implementing an event firing mechanism you should consider

The AWT event thread seems to handle the first of these but not the second. Most naive implementations of event dispatchers don't handle either.

-- JohnFarrell


Leading us to the idiom DontThrowGenericExceptions. A reasonable stricture and one that I frequently observe in the breach. :-)

-- WilliamGrosso


The way I see this is that the message from the Subject to Observer needs to be a "one way" message - it notifies the observer but doesn't return anything to the subject: no result or exceptions. Starting a new thread in java is one implementation of this. One way messages are useful for lots of things, see DougLea's ConcurrentProgrammingInJava.

Two phase check & act protocols, like JavaBeans and Smalltalk's changeRequest are a different and more difficult case.

-- JamesNoble


The main issue is what happens when an Observer is coded incorrectly and throws a RuntimeException. If the Observable is not coded defensively (i.e. does not catch (RuntimeException rte) around each call to the observer's interface), its event delivery loop will halt (and perhaps the RuntimeException propagates). This means that the other Observers do not get the event notifications. By following ObserversShouldNeverThrowExceptions, you assume the Observer is not coded defensively, as well as violating the ThrowDontCatch pattern.

I prefer to code the Observable defensively - you never know if your Observer obeys ObserversShouldNeverThrowExceptions or not. If you do this, it is not necessary to catch RuntimeException in each Observer's/listener's method.

Perhaps we need a CollectExceptions? pattern, as a special case of NestedException, to collect the exceptions caught by all the observers.


ObserversShouldNeverThrowExceptions does not mix with SomebodyElsesFramework (and neither does CheckedExceptions? for that matter). More than once, I needed to build a new control based on an existing control. Sometimes I can do GUI event interception and translation, sometimes I cannot. However, there is often an observer for a property of the original control that in some manner reflects the event that needs to be translated. So, I derive from the base class, add an observer in the constructor (thus ensuring that I see it first), and mutate properties of the object at will.

If the change is not valid, I set it back to what it was. It would be nice to throw an exception sometimes to describe why (if some code causes that particular change and not a GUI event).


-- DavidBiesack


See also ObserverPattern


CategoryException CategoryPattern


EditText of this page (last edited April 13, 2010) or FindPage with title or text search