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
- catching Throwable whenever you hand an event to another object. Who knows what stupid things it will do, and one NullPointerException can ruin your whole Thread.
- Firing off a new Thread to do the handoff to the object. The object may do take an awful long time to respond, or get into a deadlock.
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