Minden programozónak számolnia kell a hiba lehetőségével. A hibák váratlan körülmények, amelyek a program normális futásának nem részei. A leggyakoribb hibák:
A C nyelvben a hibakezelés, a hiba megkeresése és jelentése nem szokványos, ez ad-hoc és függvényenként változó, beleértve
A lehetséges hibákkal való foglalkozás, a fárasztó hibakezelés függvényhívásokhoz van rendelve. Ha hiba lépett fel, annak helyét meg kell határozni, és jelezni kell a felhasználónak felhasználóbarát formában. Ha a hiba helyben nem kezelhető le, explicit felterjesztődik az őt meghívónak. A hibaértékek hosszú listáját megfelelő formátumura kell konvertálni, hogy értelmes hibaüzenetté váljék a felhasználó számára.
A következő szempontok szükségesek egy jó hibakezelő kialakításához:
A D-ben használt hibakezelő
Először nézzünk meg néhány hibákkal kapcsolatos tapasztalatot
A megoldás hibakezelés használata. A D programozási nyelvben minden hiba osztály az absztrakt Error osztály leszármazottja. Az Error osztálynak van egy toString() virtuális függvénye, kimenete char[], amely a felhasználó számára értelmezhető leírása a hibának.
Például amennyiben a hiba típusa „out of memory”, az Error függvénye egy „out of memory” hibaüzenet küld. A függvény keres egy hibakezelő ágat. Ha ilyet talál a program végrehajtása ott folytatódik. Ha nem talál, akkor az alapértelmezett Error handler fut le, amely üzenetet küld a felhasználónak és a programot leállítja.
Hibakezelő szempontok áttekintése a D programozási nyelvben:
A try/catch/finally kifejezés sokkal szebb, mint az if (error) goto errorhandler kifejezés.
A kivételeket a try-catch-finally kifejezéssel kezeljük.
TryStatement:
try ScopeStatement Catches
try ScopeStatement Catches FinallyStatement
try ScopeStatement FinallyStatement
Catches:
LastCatch
Catch
Catch Catches
LastCatch:
catch NoScopeNonEmptyStatement
Catch:
catch ( CatchParameter ) NoScopeNonEmptyStatement
FinallyStatement:
finally NoScopeNonEmptyStatement
CatchParameter deklarál egy v változót T típussal, ahol T Object vagy Object-ből származik. V inicializálódik a throw kifejezéssel ha T ugyanolyan típusú vagy bázis osztálya a throw expression-nek. A catch ág akkor kerül végrehajtásra ha a kivétel objektum T típusú vagy T-ből származik.
Ha csak a T típus adott és nincs v változó akkor is végrehajtódik a catch ág.
Hiba ha bármely CatchParameter típusú T1 elrejti egy következő Catch ágat T2 típussal. Pl hiba, ha T1 ugyanolyan típusú vagy bázisa T2-nek.
LastCatch elkapja az összes kivételt.
A Finally utasítás mindig végrehajtásra kerül, függetlenül attól, hogy a try ScopeStatement goto, break, continue, return, exception vagy normális futás során kerül végrehajtásra.
Ha kivétel lép fel a FinallyStatement-ben és nem kezelődik le mielőtt a FinallyStatement befejeződik. Az új kivétel felülírja az éppen aktuális kivételt:
Eredmény:
Egy FinallyStatement-ből nem léphetünk ki goto, break, continue, vagy break utasítással, és nem is léphetünk bele goto-val.
Egy FinallyStatement nem tartalmazhat egyetlen Catch-et sem. (Bár ez a szigorítás enyhülhet a következő verziókban.)
Kivétel dobása:
ThrowStatement:
throw Expression ;
Az Expression kiértékelődik, és Object referencia típus lehet csak. Ez az Object referencia dobódik kivételként.
ScopeGuardStatement:
scope(exit) NonEmptyOrScopeBlockStatement
scope(success) NonEmptyOrScopeBlockStatement
scope(failure) NonEmptyOrScopeBlockStatement
A ScopeGuardStatement végrehajt egy NonEmptyOrScopeBlockStatement utasítást a kurrens scope végénél, függetlenül attól, hogy az utasítás hol helyezkedik el az aktuális scope-ban!
scope(exit): végrehajt egy NonEmptyOrScopeBlockStatement utasítást ha a scope-ot természetes módon hagyjuk el, vagy pedig kivétel által.
scope(failure): végrehajt egy NonEmptyOrScopeBlockStatement utasítást, hogy ha kivétel miatt hagytuk el.
scope(failure): végrehajt egy NonEmptyOrScopeBlockStatement utasítást, ha a scope-ot természetes módon hagytuk el.
Ha több ScopeGuardStatement is szerepel egy blokkban, akkor a megjelenésükkel fordított sorrendben hajtódnak végre. Ha bármilyen automatikus élettartamú objektum megsemmisítésre kerül a destruktor által, akkor ezek keveredhetnek a ScopeGuardStatement utasításokkal!
Egy pár példa:
{ writef("2");
scope(exit)
writef("3");
scope(exit)
writef("4");
writef("5");
}
writefln();
scope(exit) writef("1");
scope(success) writef("2");
scope(exit) writef("3");
scope(success) writef("4");
}
writefln();
this() { writef("0"); }
~this() { writef("1"); }
}
try {
scope(exit) writef("2");
scope(success) writef("3");
auto Foo f = new Foo();
scope(failure) writef("4");
throw new Exception("msg");
scope(exit) writef("5");
scope(success) writef("6");
scope(failure) writef("7");
}
catch (Exception e) { }
writefln();
A scope(exit) és scope(success) utasításokból nem lehet kilépni throw, goto, break, continue vagy return utasításokkal, és nem léphetünk bele goto-val.