Tidy Up Before Throwing

A method of an object will throw an exception if it cannot meet its post conditions. Exceptions are often caused by external errors, such as disks becoming full, a file being in an unsupported format, network connections failing, and so on. Code calling the method can catch the exception, determine how to avoid or fix the error, and invoke the object again.

If a method leaves the object in an inconsistent state when throwing an exception, client code cannot safely re-invoke that object after recovering from the exception.

If a method that throws an exception leaves the object in an inconsistent state, that object has failed to support the contract defined by its interface. There is no way that client code can invoke the object again after catching, and recovering from, an exception. Attempts to do so may (or indeed may not seemingly at random) trigger a programming error: JavaLanguage code would throw an exception derived from RuntimeException such as a NullPointerException; EiffelLanguage code would signal that a class invariant or post condition was violated; CeePlusPlus code would crash and dump core.

Therefore:

Before throwing an exception, a method should return the object to a state that meets its class invariants.

This allows client code to react meaningfully to caught exceptions because it is guaranteed that the object that raised the exception can be invoked again after rescue actions have been performed. There is less need to tidy up before throwing an exception from the constructor, because the object being constructed will be destroyed when the exception is thrown (in CeePlusPlus) or inaccessible to the code catching the exception unless the constructor has created an external reference to the new object. (in languages with GarbageCollection).

This pattern requires careful thought about the invariants of an object and the pre/post conditions of its methods, which is no bad thing.

Known uses:

The EiffelLanguage supports this pattern as a language feature. It is a run-time error if the class-invariant of the object are violated when a method finishes, even if if finishes because an exception is raised. A method can have a rescue clause that is called when an exception is raised to return the object to a safe state and optionally retry the method.

SoftwareTransactionalMemory would also provide a generic mechanism by which to restore order when failure occurs.


TidyUpBeforeThrowing sounds like a nice idiom, but I have found it difficult to implement in the past. However, the conversation in ExceptionPatterns has changed my thinking a bit.

If I have a method which can generate many exceptions, I can refactor it, placing all of the exception generating code at the start, and making sure any code which actually alters data appears after all of the exception generating code has executed successfully.

This can be applied to methods which manipulate databases fairly easily (put a "commit" at the end of the try-block and a rollback in any catch-blocks), but I'm still puzzling over how do deal with methods which deal with streams/files/network connections...

Anybody?

--DavidMcNicol

Code that reads data from streams should not, IMHO, use exceptions to indicate that it cannot understand the contents and roll the stream back for another routine to try to process the stream. Instead, exceptions should be used to signal that the stream contains erroneous data that cannot be processed by any routine. The discussion of PolymorphismVsSelectionIdiom contains descriptions of how one could dispatch processing of a stream's contents without using exceptions.

--NatPryce

Disregarding Nat for a moment, one way you can do it with streams is using a lookahead iterator. Implementing that might require you to do some buffering that you don't want to do, but then you could always throw an exception if you blow the size of your buffer ...

But in general I think Nat's got a good point. There are cleaner ways to do these things than making lots of implementation-embedded exceptions. --PeterMerel


The issues are the same for exceptions as for returning error codes. -- DaveHarris


Obviously, you don't need to tidy up before throwing an exception from the constructor, because the object being constructed will be destroyed when the exception is thrown (in CeePlusPlus) or inaccessible to the code catching the exception (in languages with GarbageCollection).

Regarding the constructor, this is not always true, try this code:

 class A
 {
    public A(B someB)
    {
        // some intitialization
        // ...
        someB.setA(this);
        // ...
        // more init stuff, here an exception happens
        // ...
        throw new Exception();
        // ...
        // final init stuff
        // ...
    }

static Main() { B b = new B(); try { A a = new A(b); } catch { } // b.myA has a valid reference to an A here, that instance was never completely constructed } } class B { A myA; public setA(A someA) { myA = someA; } }

This is a good point. In garbage collected languages, constructors must TidyUpBeforeThrowing if they create references to the constructed object that will last longer than the call to the constructor.

Note: if the code above was written in C++, it would actually leave B with a dangling pointer to raw memory because the language will destruct the new object of class A when the exception leaves the constructor.


Also see: ExceptionPatterns, YouDontWantAnExceptionYouWantaTransaction

CategoryException, CategoryPattern


EditText of this page (last edited November 1, 2007) or FindPage with title or text search