6 EXCEPTIONS 

Whenever there is a contract, the risk exists that someone will break it. This is where
exceptions come in. 

Exceptions -- contract violations -- may arise from several causes. One is assertion
violations, if assertions are monitored. Another is the occurrence of a signal triggered by the
hardware or operating system to indicate an abnormal condition such as arithmetic overflow
or lack of memory to create a new object. 

Unless a routine has made specific provision to handle exceptions, it will fail if an exception
arises during its execution. Failure of a routine is a third cause of exception: a routine that
fails triggers an exception in its caller. 

A routine may, however, handle an exception through a rescue clause. This optional clause
attempts to "patch things up" by bringing the current object to a stable state (one satisfying
the class invariant). Then it can terminate in either of two ways: 

     The rescue clause may execute a retry instruction, which causes the routine to
     restart its execution from the beginning, attempting again to fulfil its contract, usually
     through another strategy. This assumes that the instructions of the rescue clause,
     before the retry, have attempted to correct the cause of the exception. 

     If the rescue clause does not end with retry, then the routine fails: it returns to its
     caller, immediately signaling an exception. (The caller's rescue clause will be
     executed according to the same rules.) 

The principle is that a routine must either succeed or fail: either it fulfils its contract, or it
does not; in the latter case it must notify its caller by triggering an exception. 

Usually, only a few routines of a system will include explicit rescue clauses. An exception
occurring during the execution of a routine with no rescue clause will trigger a predefined
rescue procedure, which does nothing, and so will cause the routine to fail immediately,
propagating the exception to the routine's caller. 

An example using the exception mechanism is a routine attempt_transmission which tries
to transmit a message over a phone line. The actual transmission is performed by an
external, low-level routine transmit; once started, however, transmit may abruptly fail,
triggering an exception, if the line is disconnected. Routine attempt_transmission tries the
transmission at most 50 times; before returning to its caller, it sets a boolean attribute
successful to true or false depending on the outcome. Here is the text of the routine: 

     attempt_transmission (message: STRING) is 
                    -- Try to transmit message, at most 50 times. 
                    -- Set successful accordingly. 
               local 
                    failures: INTEGER 
               do 
                    if failures < 50 then 
                         transmit (message); successful := true 
                    else 
                         successful := false 
                    end 
               rescue 
                    failures := failures + 1; retry 
               end 

Initialization rules ensure that failures, a local entity, is set to zero on entry. 

This example illustrates the simplicity of the mechanism: the rescue clause never attempts to
achieve the routine's original intent; this is the sole responsibility of the body (the do clause).
The only role of the rescue clause is to clean up the objects involved, and then either to fail
or to retry. 

This disciplined exception mechanism is essential for software developers, who need
protection against unexpected events, but cannot be expected to sacrifice safety and
simplicity to pay for this protection. 
