7.1. Kivételek kezelése
7.2. Kivételek terjedése
7.3. Az exit utasítás
7.4. Elő- és utófeltételek
A programozási nyelvek eljárásai által megvalósított leképezések általában parciálisak. Ez azt jelenti, hogy még a szigorú típusellenőrzés sem tudja garantálni, hogy az eljárásokat a nekik megfelelő paraméterekkel hívjuk. A hívónak kell gondoskodni arról, hogy a paraméterek a megengedett tartományba essenek.
Robusztus az a program, melynek futása az esetleg fellépő hibák ellenére is folytatódik, valamilyen determinisztikus módon kezelve a hibás állapotot. A robusztusság egyik követelménye, hogy az eljárások totálisak legyenek. Ha az eljárás nem tudja elvégezni a neki szánt feladatot, akkor jelzi a problémát a hívónak, s rábízza a hiba kezelését.
Ahelyett, hogy minden egyes alkalommal az eljáráshívás elején megvizsgálnánk, hogy a paraméterek a megfelelő tartományba esnek-e, érdemesebb a defenzív programozást választani, azaz minden egyes eljárás legyen képes megvédeni magát a hibáktól.
proc_name = proc ( ... ) returns ( ... ) signals ( ... )A signal mögött meg kell adni a kiváltható kivételek neveit és esetleg paramétereit. Például a
search = proc ( a : array[ int ], x : int ) returns ( int ) signals ( not_int, duplicate( int ) )
div = proc ( num, denom : int ) returns ( int ) signals ( overflow, zero_divide)A paraméter nélküli kivétel kiváltása a
signal exception_namemíg a paraméterrel rendelkező kivétel kiváltása a
signal exception_name( parameter_expression )formában implementálható. Az előbbi példa kivételeinek kiváltása a
signal not_in signal duplicate( 10 )módon történhet.
Normál módon az eljárás vagy egy return utasítás hatására vagy a blokk végének elérése miatt ér véget. Kivétellel való terminálás során az eljárás befejeződése a signal utasítás hatására történik. Egy eljárás belsejében kizárólag azok a kivételek válthatók ki, amelyek fel vannak sorolva a fejléc signals részében (kivétel ez alól a failure, amiről később lesz szó).
A CLU except kulcsszava szolgál a kivétel kezelésére, melynek formája:
<statement except <handler list end
... except when exception_namel : handling_bodyl when exception_namek : handling_bodyk others : body end % exceptValós számok osztásánál például együtt kezelhető a túlcsordulás és a nullával való osztás:
z := x / y except when overflow, zero_divide : z := 0 end %exceptA duplicate kivételhez tartozó kivételkezelő ágban a paramétert is át kell venni:
... except when duplicate( i : int ) : <body % i can be used here end %exceptItt az i : int deklaráció hatásköre a kivételkezelő törzs. Minden felsorolt kivétel vissza kell hogy adjon megadott számú és típusú objektumot, sőt mindezt a formális paraméterek sorrendjének megfelelő sorrendben. Ha nem akarjuk használni a kivétel által átadott paramétert, a kivétel neve mögé (*)-ot írunk.
... except when duplicate( * ) : <body end %exceptKivételt képez a paraméter-átvétel alól az others ág. Itt elveszik az átadott objektum.
others ( name : string ) : <body
Néha a kivétel kezelése mindössze abból áll, hogy újra kiváltjuk ugyanazt a kivételt - ugyanazokkal a paraméterekkel. Erre használható a resignal utasítás, melynek formája:
resignal enamesEz azonban csak rövid formája az összes névre a megfelelő paraméterekkel kiadott except
i : search ( a, x ) resignal duplicate, not_insor teljes mértékben ekvivalens az
i : search( a, x ) except when not_in : signal not_in when duplicate ( j : int ) : signal duplicate( j ) end %exceptprogramrészlettel.
except when failure : signal failure( s ) others ( s : string ) : signal failure( "unhandled exception" || s ) end %except
exit exception_name( parameter_expression )Hatására a vezérlés átadódik az ugyanabban a törzsben levő, az exit után következő első, az adott kivételt lekezelő except ágra. A megadott kivételnévnek valamelyik except utasításban szerepelni kell..
Az exit által kiváltott kivételt nem kell definiálni a fejlécben (a hatása lokális), de csak egy explicit módon megadott kivételkezelő ágra lehet így hivatkozni, failure-ra nem és automatikus kivételtovábbadás sem történhet.
A nyelv lehetőséget ad elő- és utófeltételek használatáhoy. Ez a kivételkezeléshez is további kellemes eszközt ad a programozónak. A CLU specifikációja az alábbiakban ismertetett szintaktikai cukrot tartalmazza, mely olvashatóvá teszi és leegyszerűsíti az elő- és utófeltételek megadását.
Előfeltételek megadása:
modifies at most (<obj_list>) new(<obj>) returns % procedure returns in normal way (ie. does not abort, loop or signal) signals <name> % procedure raises given exception (which must be listed in proc. header)
Utófeltételek megadása:
normally <post_pred> except signals <except1> when <pre1> ensuring <post1> ... signals <exceptN> when <preN> ensuring <postN>
Az ezzel ekvivalens forma:
(returns | signals <except1> | ... | signals <exceptN>) & (returns => <post_pred> & ~(<pre1>|...|<preN>)) & (signals <except1> => (<pre1> & <post1>)) & ... (signals <exceptN> => (<preN> & <postN>))
Az ensuring klóz értéke opcionális, alapértelmezés szerint TRUE.
Ez a felírás azt is jelenti, hogy CLU-ban megengedett a kivételek nem-determinisztikus kiváltása.