Allen Mechanismen für Ausnahmenbehandlungen ist gemein, daß eine Prozedur auf verschiedenen Wegen beendet werden kann. Um die Diskussion zu vereinfachen, kann man jede Anweisung als einen Prozeduraufruf betrachten, selbst wenn der Übersetzer dafür keine Prozeduraufrufe generiert. Bei einigen Programmiersprachen ist es auch in diesem Zusammenhang sinnvoll, lokale Blöcke als lokale Prozeduren zu betrachten (insbesondere C++ und Modula-3).
Entweder wird eine Prozedur normal beendet oder sie initiiert eine Ausnahmenbehandlung aufgrund eines entdeckten Ausfalls. Eine Ausnahmenbehandlung führt dazu, daß die Kontrolle an einen Ausnahmenbearbeiter weitergeleitet wird. Die Prozedur, die die Ausnahmenbehandlung initiiert hat, wird als Signalgeber bezeichnet. Die Prozedur, die den Ausnahmenbearbeiter enthält, der aufgrund der Ausnahmenbehandlung aktiviert wird, heißt Signalempfänger.
Es gibt eine Reihe von Techniken, einen Signalempfänger zu lokalisieren. Denkbare Kandidaten sind aktivierte Prozeduren (also der Klient und der Klient des Klienten usw.), statisch übergeordnete Prozeduren, globale und damit kontextunabhängige Ausnahmenbearbeiter und objektbezogene Bearbeiter, die von einem der Parameter des Signalgebers abhängen. Der Signalgeber selbst wird als Signalempfänger nicht in Betracht gezogen, da er per Definition dazu nicht in der Lage ist.
Wenn der Signalempfänger eine der aktivierten Prozeduren sein soll, so kann dies der direkte Aufrufer sein (Ebenenmodell oder single level mechanism) oder einer der übergeordneten Klienten (distanziertes Ebenenmodell oder multilevel mechanism), d.h. im Beispiel könnte A der Signalempfänger für den Signalgeber C sein, ohne daß B daran beteiligt ist. Da dies zum Bruch von Abstraktionsgrenzen führt, wird dies von kaum einer Sprache unterstützt (PL/1 ist eine Ausnahme). BETA unterstützt das distanzierte Ebenenmodell nur in Bezug auf statisch übergeordnete Klienten und vermeidet damit auf elegante Weise den Bruch von Abstraktionsgrenzen.
Globale Ausnahmenbearbeiter sind einfach zu implementieren und benötigen keine zusätzliche Sprachunterstützung, wenn es Prozedurtypen gibt. Allerdings können sie im Bereich von Bibliotheken oder größeren Software-Systemen nicht die einzige Lösung sein.
Einige objekt-orientierte Sprachen (z.B. Eiffel oder Lore) unterstützen objektbezogene Ausnahmenbearbeiter.
Ausnahmenbearbeitern stehen - nach einigen normalen Anweisungen - folgende Optionen offen (siehe Abbildung 5.3.3):
Von der Sprache unterstützte Ausnahmenbehandlungen können einige der genannten Probleme der traditionellen Technik lösen. Als ein Beispiel mag in Modula-3 die Prozedur PutChar aus dem Modul Wr dienen:
(* excerpt of the interface of module Wr *) TYPE Code = {Closed, Unseekable}; EXCEPTION Failure(REFANY); Error(Code); PROCEDURE PutChar(wr: T; ch: CHAR) RAISES {Failure, Error};
Die RAISES-Deklaration gibt an, daß PutChar entweder erfolgreich beendet wird oder PutChar eine der angegebenen Ausnahmen (Failure oder Error) initiiert. Beide Ausnahmen sind parametrisiert: Failure durch REFANY, einen Typ, der zu allen Zeigertypen kompatibel ist, und Error durch Code. In dem Beispiel initiiert PutChar selbst nur Error, während Failure von den zugrundeliegenden Implementierungen ausgelöst werden kann.
Ein Klient von Wr könnte folgendermaßen aussehen:
PROCEDURE SomeOperation(...) RAISES {Wr.Failure, Wr.Error, ...}; VAR failure: REFANY; code: Wr.Code; BEGIN (* ... *) TRY PutChar(wr, ch); EXCEPT | Wr.Failure(failure) => TYPECASE failure OF | FileStream.Failure => (* ... *) (* ... *) END; | Wr.Error(code) => (* ... *) END; END SomeOperation;
Hierbei wird mit TRY...EXCEPT...END eine Folge von Anweisungen mit einem Ausnahmenbearbeiter verknüpft. Der Ausnahmenbearbeiter hat die Möglichkeit, zwischen den einzelnen Ausnahmen zu unterscheiden und auf die zugehörigen Parameter zuzugreifen. Wenn notwendig, kann der Ausnahmenbearbeiter auch alle weiteren und möglicherweise unbekannten Ausnahmen abfangen.
Ada unterstützt keine Parametrisierungen von Ausnahmen, und Eiffel läßt nur einen STRING-Parameter zu. In Eiffel bezieht sich ein Ausnahmenbearbeiter immer auf eine vollständige Prozedur und nicht auf eine beliebige Anweisungsfolge innerhalb der Prozedur. Darüber hinaus erlaubt Eiffel den Ausnahmenbearbeitern nur Neustarts oder eine Weiterleitung der Ausnahme. Dies soll zwar ein stilles RETURN verhindern, allerdings ist es möglich, dies über einen Neustart zu simulieren.
Während diese eingebauten Mechanismen eine mächtige Kontrollstruktur für Ausnahmenbehandlungen sind, können sie genauso für große Sprünge über Prozedurgrenzen hinweg mißbraucht werden (analog zu longjmp in C). Im Falle von tief verschachtelten Ausfällen ist weder die detaillierte Fehlermeldung der unten liegenden Prozedur noch die Fehlerindikation auf der höheren Abstraktionsebene allein ausreichend, um eine aussagefähige Fehlermeldung zusammenzustellen. Für lesbare Fehlermeldungen wäre eine Beschreibung des Verlaufs der Ausfälle interessant. Im Beispiel: A fiel aus, da B wegen des Ausfalls von C ausfiel.
Modula-3, Eiffel und Exceptional C versuchen, auch asynchrone Ereignisse (wie z.B. SIGINT unter UNIX) als Ausnahmen zu behandeln. Hier erweist sich jedoch ein Modell auf Basis von Ereignissen und Interessenten als günstiger (wie es in der Ulmer Oberon-Bibliothek als Events realisiert ist),5.4da es wichtig ist, daß asynchrone Ereignisse, die nicht aufgrund von Fehlern entstehen, unabhängig vom lokalen Kontext bearbeitet werden. Sonst kann es im Ebenenmodell passieren, daß keine der aktivierten Prozeduren darauf vorbereitet ist, oder daß eine ungestörte Fortsetzung nach der Bearbeitung unmöglich ist.