eiffel: analysis, design and...
TRANSCRIPT
Eiffel: Analysis, Design and ProgrammingETH Zurich, September-December 2008
-6--6-
Exception handling
What is an exception?
“An abnormal event”
Not a very precise definition
Informally: something that you don’t want to happen
Exception vocabulary
� “Raise”, “trigger” or “throw” an exception
� “Handle” or “catch” an exception
How to use exceptions?
Two opposite styles:
� Exceptions as a control structure:Use an exception to handle all casesother than the most favorable ones
(e.g. a key not found in a hash table triggers(e.g. a key not found in a hash table triggersan exception)
� Exceptions as a technique of last resort
(From an Ada textbook)
sqrt (x : REAL) return REAL isbegin
if x < 0.0 thenraise Negative ;
elsenormal_square_root_computation ;
How not to do it
normal_square_root_computation ;end
exceptionwhen Negative =>
put ("Negative argument");return;
when others => …end; -- sqrt
Dealing with erroneous cases
Calling a.f (y ) withf (x : T )
requirex.pre
do…
ensure.
ensureResult.pre
end
Normal way (a priori scheme) is either:
1. if y.pre then a.f (y ) else …Error case… end
2. ensure_pre ; a.f (y)
A posteriori scheme
a.try_to_invert (b)if a.could_invert then
x := a.invertedelseelse
… Error case …
end.
C++, Java, C#: raising programmer-defined exception
Instruction:
throw my_exception;
try … catch (Exception e) …
try … finally …
The enclosing routine should be of the form
my_routine (…) throws my_exception {my_routine (…) throws my_exception {
…
if abnormal_condition
throw my_exception;
}
The calling routine must handle the exception (even if the handling code does nothing).
How not to do it: Java
b= ? Normal or Exception?b= 4 Normal Does this program compile in C#?
Example: Return and finally
Return 2
Example: Return and finally
return= ? return=1b=?b=2
Checked vs unchecked exceptions
Checked: raised by program, caller must handle
Unchecked: usually raised by external sources, don’t have to be handled
Exception handling: another approach
Introduce notion of contract
The need for exceptions arises when a contract is broken by either of its parties (client, supplier)
Two concepts:Two concepts:
� Failure: a routine, or other operation, is unable to fulfill its contract.
� Exception: an undesirable event occurs during the execution of a routine — as a result of the failure of some operation called by the routine.
The original strategy
r (...)require
...do
op1op2...opopi...opn
ensure...
end
Not going according to plan
r (...)require
...do
op1op2...op Fails, triggering an exception in ropi...opn
ensure...
end
Fails, triggering an exception in r(r is recipient of exception).
Causes of exceptions in O-O programming
Four major kinds:
� Operating system signal: arithmetic overflow, no more memory, interrupt ...
� Assertion violation (if contracts are being monitored)� Assertion violation (if contracts are being monitored)
� Void call (x.f with no object attached to x)
� Programmer-triggered Not any more in Eiffel & Spec#
Handling exceptions properly
Exception handling principle
There are only two acceptable ways to react for the recipient of an exception:
� Failure: Concede impossibility of fulfilling contract, and trigger an exception in the callerand trigger an exception in the caller
(also called Organized Panic).
� Retry: Try again, using a different strategy (or repeating the same one)
(Rare third case: false alarm)
The call chain
r0
r1
r2
r3
r4
Routine call
Exception mechanism
Two constructs:
� A routine may contain a rescue clause.
� A rescue clause may contain a retry instruction.
A rescue clause that does not execute a retry leads to failure of the routine (this is the organized panic case).failure of the routine (this is the organized panic case).
Exception mechanism (2)
f (...)require
preconditionlocal
… local entity declarations…do
bodydo
bodyensure
postconditionrescue
rescue_clauseend
If no exception clause (1)
Absence of a rescue clause is equivalent, in a first approximation, to an empty rescue clause:
f (...)do
...end
is an abbreviation for
f (...)f (...)do
...rescue
-- Nothing hereend
(This is a provisional rule; see next.)
Transmitting over an unreliable line (1)
Max_attempts : INTEGER is 100
attempt_transmission (message : STRING) is-- Transmit message in at most -- Max_attempts attempts.
localfailures : INTEGER
dodounsafe_transmit (message)
rescue
failures := failures + 1if failures < Max_attempts then
retry
endend
Transmitting over an unreliable line (2)
Max_attempts : INTEGER is 100
failed : BOOLEAN
attempt_transmission (message: STRING) is-- Try to transmit message; -- if impossible in at most Max_attempts-- attempts, set failed to true.
localfailures: INTEGER
dodoif failures < Max_attempts then
unsafe_transmit (message)else
failed := Trueend
rescuefailures := failures + 1retry
end
Another Ada textbook example
procedure attempt is begin<<Start>> -- Start is a labelloop
beginalgorithm_1;exit; -- Alg. 1 success
exceptionwhen others =>
begin
attemptlocaleven: BOOLEAN
doif even thenalgorithm_2
In Eiffel
beginalgorithm_2;exit; -- Alg. 2 success
exceptionwhen others =>
goto Start;end
endend
end main;
if even thenalgorithm_2
elsealgorithm_1
endrescueeven := not evenRetry
end
Dealing with arithmetic overflow
quasi_inverse (x: REAL): REAL-- 1/x if possible, otherwise 0
localdivision_tried: BOOLEAN
doif not division_tried then
Result := 1/xResult := 1/xend
rescuedivision_tried := TrueRetry
end
Max_attempts: INTEGER is 100failed : BOOLEAN
attempt_transmission (message: STRING) is-- Transmit message in at most -- Max_attempts attempts.
localfailures: INTEGER
dounsafe_transmit (message)
Transmitting over an unreliable line (3)
unsafe_transmit (message)rescue
failures := failures + 1if failures < Max_attempts then
retryendfailed := true …
end
fromunsafe_transmit (message)
untilnot exceptions
loopfailures := failures + 1if failures < Max_attempts then
continue l
Pseudo code
continue lendfailed := true … raise exceptionl: unsafe_transmit (message)
end
Retry allows to transfer control flow to the beginning of a routine without executing the rest of the rescue block
ETL3: Exception mechanism
Two constructs:
� A routine may contain a rescue clause
� A rescue clause may set the Retry boolean variable
A rescue clause that ends with Retry not set leads to failure of the routine (“organized panic”).failure of the routine (“organized panic”).
ETL3:Transmitting over an unreliable line (1)
Max_tries : INTEGER = 100attempt_transmission_1 (message : STRING )
localfailures : INTEGER
do
-- Transmit message in at most Max_tries attempts.
dounsafe_transmit (message)
rescuefailures := failures + 1Retry := (failures < Max_tries)
end
ETL3: Transmitting over an unreliable line (2)
Max_tries : INTEGER = 100attempt_transmission_2 (message : STRING )
localfailures : INTEGER
do
-- Try to transmit message in at most Max_tries-- attempts; if impossible, set could_not to True.
; could_not:BOOLEAN
if failures < Max_tries thendo
rescue
Retry := True end
if failures < Max_tries thenunsafe_transmit (message)
elsecould_not := True
end
ETL3: Dealing with arithmetic overflow
quasi_inverse (x: REAL): REAL-- 1/x if possible, otherwise 0
localdivision_tried: BOOLEAN
doif not division_tried then
Result := 1/xResult := 1/xend
rescuedivision_tried := TrueRetry := True
end
The correctness of a class
For every exported routine r :
{INV and Prer } dor {INV and Postr }
For every creation procedure cp :
a.f (…)
a.g (…)
create a.make (…)S1
S2
For every creation procedure cp :
{Precp } docp {INV and Postcp}a.f (…)
S3
S4
Exception correctness
For the normal body:
{INV and Prer } dor {INV and Postr }
For the exception clause:
{??? } rescue {??? }{??? } rescuer {??? }
Exception correctness
For the normal body:
{INV and Prer } dor {INV and Postr }
For the exception clause:
{True } rescue {INV }{True } rescuer {INV }
If no exception clause (2)
Absence of a rescue clause is equivalent to a default rescue clause:
f (...)do
...end
is an abbreviation for
f (...)f (...)do
...rescue
default_rescueend
The task of default_rescue is to restore the invariant.
For finer-grain exception handling
Exceptions are objects
Library mechanisms to raise exceptions, distinguish between exception types, and access details of an exception
The full rule
{Q’} r {INV ∧ (Retry ⇒ P )∧ (¬ Retry ⇒ R ) | INV ∧ R }
P⇒ P
___________________________________________
“Retry invariant”
| Q’{INV ∧ P } b {INV ∧ Q } ‘‘
‘{Q’} r {INV ∧ (Retry ⇒ P )∧ (¬ Retry ⇒ R ) | INV ∧ R }___________________________________________
{INV ∧ P } do b rescue r end {INV ∧ Q
Error postconditionNormal postcondition
} | INV ∧ R
‘
Summary and conclusion
Exceptions as a control structure (internally triggered):
Benefits are dubious at best
An exception mechanism is needed for unexpected external events
Need precise methodology; must define what is “normal” and “abnormal”. Key notion is “contract”.
Next challenge is concurrency & distribution
Further reading
Bertrand Meyer: Object-Oriented Software Construction, 2nd edition, Prentice Hall, 1997
Chapter 12: When the contract is broken: exception handling
Bertrand Meyer: Eiffel: The LanguageBertrand Meyer: Eiffel: The Languagehttp://se.inf.ethz.ch/~meyer/ongoing/etl/
Chapter 26: Exception handling