-5- exception handling what is an exception? “an abnormal event” not a very precise definition...
Post on 19-Dec-2015
220 views
TRANSCRIPT
What is an exception?
“An abnormal event”
Not a very precise definition
Informally: something that you don’t want to happen
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
an 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 ;
endexception
when Negative =>put ("Negative argument");return;
when others => end; -- sqrt
How not to do it
Dealing with erroneous cases
Calling a.f (y ) with
f (x : T )require
x.predo
…ensure
Result.preend
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)
C++, Java, C#: raising programmer-defined exception
Instruction:throw my_exception;try … catch (Exception e) …try … finally …
The enclosing routine should be of the formmy_routine (…) throws my_exception {
…if abnormal_condition
throw my_exception;}
The calling routine must handle the exception (even if the handling code does nothing).
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:
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.
Not going according to plan
r (...)require
...do
op1
op2
...opi
...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)
Void call (x.f with no object attached to x)
Programmer-triggeredNot 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 caller
(also called Organized Panic).
Retry: Try again, using a different strategy (or repeating the same one)
(Rare third case: false alarm)
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).
Exception mechanism (2)
f (...)require
preconditionlocal
… local entity declarations…do
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 (...)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
dounsafe_transmit (message)
rescuefailures := failures + 1if failures < Max_attempts then
retryend
end
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
doif 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 begin algorithm_1; exit; -- Alg. 1 success exception when others => begin algorithm_2; exit; -- Alg. 2 success exception
when others => goto Start; end
end endend main;
attemptlocal
even: BOOLEANdo
if even thenalgorithm_2
elsealgorithm_1
endrescue
even := not evenRetry
end
In Eiffel
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/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)
rescuefailures := failures + 1if failures < Max_attempts then
retryend failed := true …
end
Transmitting over an unreliable line (3)
fromunsafe_transmit (message)
untilnot exceptions
loopfailures := failures + 1if failures < Max_attempts then
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
Pseudo code
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”).
ETL3:Transmitting over an unreliable line (1)
Max_tries : INTEGER = 100attempt_transmission_1 (message : STRING )
localfailures : INTEGER
dounsafe_transmit (message)
rescue failures := failures + 1
Retry := (failures < Max_tries) end
-- Transmit message in at most Max_tries attempts.
ETL3: Transmitting over an unreliable line (2)
Max_tries : INTEGER = 100attempt_transmission_2 (message : STRING )
localfailures : INTEGER
do
rescue
Retry := True end
-- Try to transmit message in at most Max_tries -- attempts; if impossible, set could_not to
True.
; could_not:BOOLEAN
if failures < Max_tries thenunsafe_transmit
(message)else
could_not := Trueend
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/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 :
{Precp } docp {INV and Postcp}
a.f (…)
a.g (…)
a.f (…)
create a.make (…)S1
S2
S3
S4
Exception correctness
For the normal body:
{INV and Prer } dor {INV and Postr }
For the exception clause:
{??? } rescuer {??? }
Exception correctness
For the normal body:
{INV and Prer } dor {INV and Postr }
For the exception clause:
{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 (...)do
...rescue
default_rescueend
The task of default_rescue is to restore the invariant.
For finer-grain exception handling
Exceptions are objectsLibrary 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
___________________________________________
{INV P } do b rescue r end {INV Q
Error postcondition
Normal postcondition
“Retry invariant”
| Q’{INV
P }
b {INV Q
}
}
| 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