Diskussion:Programmierkurs: Delphi: Pascal: Exceptions

Letzter Kommentar: vor 14 Jahren von Dannys9 in Abschnitt Sinn von Exceptions

Sinn von Exceptions

Bearbeiten

Wenn Exceptions in Delphi ungefähr so funktionieren wie in Python oder in C++, ist der letzte Absatz fragwürdig. Exceptions machen Quellcode übersichtlicher (deshalb wurden sie ja so bejubelt) und sind nur in sehr seltenen Fällen ein Performance-Hindernis. Daher ist die Schlußfolgerung, daß man sie vermeiden sollte wo geht, in meinen Augen falsch. Das Gegenteil ist der Fall. – Bronger 17:49, 30. Sep. 2010 (CEST)Beantworten

Du hast recht: der letzte Absatz klingt seltsam. Es ist aber korrekt, dass Exceptions vermieden werden sollten, wenn man sie vermeiden kann. Mit Exceptions sollen (unvorhersehbare) Ausnahmesituationen behandelt und damit verhindert werden, dass das Programm insgesamt abschmiert (womöglich noch ohne konkrete Fehlermeldung). Es geht aber nicht darum, sie zur Prüfung vorhersehbarer Probleme (wie der Division durch Null) zu missbrauchen.
"Performance-Hindernis" ist etwas übertrieben. Sie sind aber in aller Regel eine Bremse. Einfacher und deutlich schneller geht es mit einer vorherigen Abfrage statt einer nachträglichen Reaktion. -- Jürgen 18:02, 30. Sep. 2010 (CEST)Beantworten
Aber ist der Performance-Verlust wirklich ein Thema, wenn man ohnehin nur zwei Seiten über Exceptions schreibt? Die Fälle, in denen man mit Exceptions ein Programm für den Benutzer spürbar ausbremst, sind selten. Ich habe sowas noch nie gesehen. Aber das ist auch eher ein Nebenpunkt.
Das größere Problem ist, daß Exceptions in diesem Text als eine Alternative zum lokalen Überprüfen von Vorbedingungen dargestellt wird. Daß also quasi diese beiden Ansätze in Konkurrenz zueinander stehen. Das ist so nicht! Der entscheidende Vorteil des Ausnahme-Konzepts ist, daß Ausnahmen über Schachtelungen hinweg sich automatisch "eskalieren". Man kann so aus einer verschachtelten Schleife springen, oder – noch viel häufiger – eine Ausnahme auswerfen und die Fehlerbehandlung dem Ausrufer (oder dem Aufrufer des Aufrufers etc.) überlassen. Das ging vorher nur über mühsames nach-oben-reichen von Rückgabe-Fehlerwerten.
Ich kann den Artikel aber nicht reparieren, weil ich Exceptions nur von C++ und Python kenne. Vielleicht ist Delphi da wirklich anders. – Bronger 22:55, 30. Sep. 2010 (CEST)Beantworten
Meiner Meinung nach stehen diese beiden Konzepte in Konkurrenz zu einander. Der Ansatz "vorherige Prüfung" vermeidet ein Problem, während eine Exception ein potenzielles Problem zulässt und im nachhinein Korrekturen vornimmt. Mache ich das eine, ist das jeweils andere nicht nötig. Das mit der Performance kommt vielleicht in dem Abschnitt missverständlich rüber, mal davon abgesehen, dass das bei heutigen Rechnern wohl sowieso kaum eine Rolle spielt. Die Exception-Behandlung selbst verbraucht natürlich wenig Ressourcen. Ich meinte eher, dass hierbei die Behandlung nach einem Fehler erfolgt, also schon mehrere Aufrufe davor ausgeführt wurden und zum Aufräumen natürlich auch danach. Bei einer Vorabprüfung würden diese ganzen Aufrufe gar nicht erst stattfinden.
Dein Beispiel, mit Exceptions schnell aus verschachtelten Schleifen auszusteigen, ist eher ein Missbrauch des Zwecks von Exceptions (auch wenn er mir irgendwie gefällt). Das funktioniert natürlich auch in Delphi. Genausogut könnte man bei einem Fehler in der innersten Schleife zu einem Label außerhalb aller Schleifen springen – diese Programmierweise haben wir doch schon lange hinter uns  . Nichts anderes passiert, wenn du an der gleichen Stelle stattdessen eine Exception auslöst. Ich hatte nur den klassischen Vorgang im Sinn, dass eine aufgerufene Routine eine Exception auslöst, weil die Umgebung für diese Routine fehlerhaft ist. Meistens – so meine Erfahrung – wird nämlich empfohlen, um alle möglichen Aufrufe eine Exception-Behandlung zu setzen, bspw. beim genannten Öffnen einer Datei und ähnlichen Banalitäten. Das halte ich persönlich für absolut unsinnig.
Ich bin gerade dabei, das Buch grundlegend zu überarbeiten. Wenn du Lust hast, kannst du mir gern einen Vorschlag machen, wie du das für C++ formulieren würdest. Wir können das dann auf Delphi umschreiben. Ich würde mich freuen! -- Dannys9 17:37, 1. Okt. 2010 (CEST)Beantworten
Das verpönte GOTO wird durchaus zum herausspringen aus einer inneren Schleife geduldet, zumindest im Linux-Kernel. Das ist vielleicht der einzige Fall, für den es noch interessant ist.
Bei Ausnahmen ist ganz wichtig, daß man herausarbeitet, daß sie häufig in der aufrufenden Funktion – oder noch darüber – aufgefangen werden. Man spart sich so die Rückgabewerte, die u.U. sogar nach oben weitergereicht werden müssen.
Beispiel: Ich will in einer Funktion den Mittelwert der Zahlen berechnen, die in der übergebenen Datei stehen. Was mache ich, wenn die leer ist? Gut, vielleicht NaN zurückgeben, aber dann weiß der Aufrufer nicht, ob die Datei nicht gefunden wurde, leer war oder nur Buchstaben enthielt. Mit Ausnahmen kann ich das sehr elegant und beliebig präzise nach oben reichen. U.U. fühlt sich erst eine OnIrgendwas-Routine zuständig, fängt die Ausnahme und gibt eine MessageBox aus.
Hinzu kommt, daß man nicht alles sinnvoll vorher prüfen kann. Im Kapitel ist beispielsweise EDivByZero einfach zu vermeiden, ERangeError wird aber viel einfacher als Ausnahme aufgefangen.
In Python, was meine Heimatsprache ist, werden Ausnahmen exzessiv benutzt. Dort gilt der Spruch "Leap before you look" – "springe, bevor zu guckst". Man schreibt also ganz gerne
try:
    print array[i]
except IndexError:
    print "Dieses Element gibt es nicht!"
anstelle von
if i < len(array):
    print array[i]
else:
    print "Dieses Element gibt es nicht!"
Letztlich ist das eine Mentalitätsfrage, aber die erste Version hat schon schöne Eigenschaften: (a) Man trennt den Code, der nur die Scheiße aufwischen soll, deutlich vom Rest. (b) Vorabchecken kann wesentlich komplizierter werden als die beiden try/except-Zeilen. (c) Und schließlich wird die Bereichsüberprüfung ja ohnehin vom Interpreter bzw. Prozessor gemacht, man braucht es also nicht nochmal zu tun. – Bronger 03:06, 3. Okt. 2010 (CEST)Beantworten
Es stimmt, in manchen Situationen ist es einfacher und übersichtlicher, eine Exception zu behandeln statt eine Vorabprüfung vorzunehmen, z.B. wenn das eine mehrzeilige If-Abfrage bedeuten würde. Diesen Vorteil werde ich noch ins Kapitel einbauen. Eine Exception nach oben durchzureichen und erst in einer höheren Ebene zu behandeln, ist im Einzelfall durchaus ein Feature. Auch das werde ich versuchen, besser hervorzuheben.
Dein Mittelwert-Beispiel entspricht im Übrigen meiner klassischen Vorstellung einer Exception. Hier ist es dem Programm im Vorwege nicht oder nur mit ungeheurem Aufwand möglich, eine Vorabprüfung des Dateiinhalts durchzuführen, zumal dieser dann doppelt eingelesen und ausgewertet werden müsste. Man könnte es ohne vorherige Prüfung und Exceptionbehandlung programmieren, indem man einen Status als Rückgabewert liefert und das Ergebnis als Parameter call-by-reference übermittelt. Klar, dann könnte man natürlich die Funktion zum einen nicht direkt in Berechnungen verwenden sondern müsste das Ergebnis immer zwischenspeichern. Zum anderen müsste man nach Aufruf der Routine den Rückgabewert prüfen. Hier eignet sich eine Exceptionbehandlung daher deutlich besser. -- Dannys9 13:59, 3. Okt. 2010 (CEST)Beantworten
Ich habe den Abschnitt jetzt mal abgeändert. Ist es so besser? -- Dannys9 21:02, 3. Okt. 2010 (CEST)Beantworten
Soweit ich da überhaupt kompetent bin, ist das super so. – Bronger 19:06, 8. Okt. 2010 (CEST)Beantworten
Danke für die Rückmeldung. -- Dannys9 19:50, 11. Okt. 2010 (CEST)Beantworten
Zurück zur Seite „Programmierkurs: Delphi: Pascal: Exceptions“.