Kivételkezelési mechanizmus
Az Aikido nyelvbe épített mechanizmussal segíti a kivételkezelést (C++ és Java alapú). Az alapötlet, hogy ha nem várt esemény történik,
egy kivétel objektum váltódik ki az adott helyen. A kivétel a hívási vermen keresztül továbbítódik egészen az első olyan függvényig, ami
a megfelelő módon kezeli a helyzetet. Ha egy kivételkezelőhöz ért, az kezelheti helyben, illetve továbbdobhatja a kivétel objektumot. Ha a
hívási lánc végére értünk, és a kivételt nem kezeltük sehol, a program terminál.
Kivételek kiváltása és elkapása
A kivételek kiváltására a throw utasítást, elkapásukra a try - catch blokkot.
Példa:
try {
login(user, password)
System.println("User" + user.getName() + " logged in")
service(user)
} catch (e) {
log("Login for + " user.getName() + " failed due to: " + e)
return
}
A
try blokkon belül meghívjuk a
login() függvényt, ami egy felhasználót és egy jelszót kap paraméterként.
Ha a bejelentkezés sikeres, a
servive() függvény is meghívódik. Ha a bejelentkezés sikertelen (például rossz jelszót adtunk meg),
a kivételkezelőhöz kerül a végrehajtás. A kivételkezelő elkapja a dobott kivételt
(e) , és loggolja a probléma okát.
A
C++-szal vagy
Java-val ellentétben, az
Aikidoban csak egy
catch ág lehet -
a nyelv dinamikus típusossága miatt. Ez a mechanizmus nem kevésbé használható, mint az említett nyelvekben lévő, csak más jellegű. A
C++-ban a típusösszehasonlítás a kivétel kiváltása és a kivétel elkapása között történik. A kivételkezelő csak akkor hívódik meg,
ha a kivétel típusa megegyezik a várt típussal. Ezzel szemben az
Aikido-ban mindig meghívódik a kivételkezelő, átadva a kivétel
"típusának" meghatározását a kivételkezelő kódnak.
Példa:
const BAD_PASSWORD = 1 //password mismatch
const TOO_MANY_USERS = 2 //too many users logged in
const USER_BARRED = 3 //user has been barred from logging in today
try {
login() //try to log in
//etc.
} catch (e) {
if(typeof(e) == typeof(int) && e < 0) { //test for type and value
System.println("server failure, have to exit")
System.exit(e)
} elif (typeof(e) == typeof(int)) {
switch(e) {
case BAD_PASSWORD:
System.println("Invalid password, try again")
continue //allow a retry
case TOO_MANY_USERS:
System.println ("Too many users, try again later")
return
case USER_BARRED:
System.println ("You are barred, try again tomorrow")
return
}
}elif (typeof (e) == "string") { //got a string?
System.println ("Failed to login due to: " + e)
return
}else {
throw e //rethrow exception to caller
}
}
Az
Aikido-ban bármilyen értéken használhatunk kivételként. Az alábbi kivételdobások mind
megengedettek:
throw 1 //an integer 1
throw "invalid password" //a string
throw InvalidPassword() //an object
throw getException(1) //something returned from a function
throw false
throw null
throw new Exception("Invalid password")
throw InvalidPassword //a class
Kezeletlen kivételek
Mi történik, ha egy kivétel a hívási lánc végére ér? Definiáljuk először mit is jelent a végrehajtási verem.
A programban minden szál fenntart egy saját vermet. A végrehajtás minden pontján a verem információkat tartalmaz az aktuális állapotról (pl.
a visszatérési értéket, a lokális változókat, stb).
A végrehajtási veremnek van alja és teteje. Az alján a szál által először hívott függvény (illetve maga a szál függvény) van. A verem teteje
folyton változik, de mindig az aktuálisan vérehajtott függvényről tartalmaz információt.
Amikor egy kivétel keletkezik, a végrehajtó szál a verem tetejétől indulva keresi a kivételkezelő kódot. Minden alkalommal, mikor egy szinttel
lejebb haladunk a veremben, az éppen elhagyott rész kikerül a veremből (megsemmisülnek a lokális változók, stb).
Ha elérjük a verem alját anélkül, hogy a kivételt elkaptuk volna, akkor a program befejezi a futást (nem csak az aktuális szál terminál, hanem
minden futó szál és ezáltal az egész program).
A kezeletlen kivételek hatására az interpreter a "runtime error" üzenetet írja a standard error stream-re.
Kivételek és futásidejű hibák
Az Aikido program futásakor vannak olyan esetek, amikor maga az interpreter dob kivételt. Ezek ugyan úgy elkaphatók mielőtt
a program abortálását okoznák, mint bármely más kivétel.
Az interpreter által dobott kivételek típusa lehet string vagy a System.Exception osztály (vagy
belőle származó osztály) egy példánya.
Például, a System csomag openin() függvénye megkísérel megnyitni egy fájlt, és siker esetén egy streammel tér
vissza. Sikertelen próbálkozás esetén (pl. nem létezik a fájl, nem elérhető, stb) az openin() függvény
System.FileException típusú kivételt dob.
Példa:
try {
var instream = System.openin("chatrc")
processRCFile(instream)
} catch (e) {
//can't open file, ignore
}