Eiffel: Analysis, Design and...

Post on 21-Jun-2018

219 views 0 download

Transcript of Eiffel: Analysis, Design and...

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