Warum ist die Ausnahmebehandlung schlecht?

90

Googles Go-Sprache hat keine Ausnahmen als Design-Wahl, und Linus von Linux hat Ausnahmen Mist genannt. Warum?

Joemoe
quelle
2
Der Schöpfer von ZeroMQ schreibt darüber, wie er denkt, dass es ein Fehler war, es in C ++ zu schreiben (hauptsächlich wegen der Fehlerbehandlung). 250bpm.com/blog:4
serbaut
Go hat möglicherweise keine Ausnahmen, aber es gibt "Panics", von denen Sie "wiederherstellen" können (während zurückgestellte Anweisungen noch ausgeführt werden) und die einen nicht lokalen Kontrollfluss bieten ...
Kerrek SB
Hier ist ein schöner Artikel leichterra.com/papers/exceptionsharmful (Ausnahmebehandlung als schädlich)
masterxilo
Afaics, Ausnahmen können in Go mit einer signifikanten Boilerplate simuliert werden , obwohl dieser Punkt für das Transpilieren von einem Syntaxzucker sinnvoller sein kann als für das manuelle Schreiben der Boilerplate.
Shelby Moore III

Antworten:

82

Ausnahmen machen es wirklich einfach, Code zu schreiben, bei dem eine ausgelöste Ausnahme Invarianten aufbricht und Objekte in einem inkonsistenten Zustand belässt. Sie zwingen Sie im Wesentlichen dazu, sich daran zu erinnern, dass fast jede Aussage, die Sie machen, möglicherweise werfen und richtig damit umgehen kann. Dies kann schwierig und kontraintuitiv sein.

Betrachten Sie so etwas als einfaches Beispiel:

class Frobber
{
    int m_NumberOfFrobs;
    FrobManager m_FrobManager;

public:
    void Frob()
    {
        m_NumberOfFrobs++;

        m_FrobManager.HandleFrob(new FrobObject());
    }
};

Unter der Annahme , das FrobManagerwird deletedas FrobObject, das sieht OK, nicht wahr? Oder vielleicht auch nicht ... Stellen Sie sich dann vor, ob entweder FrobManager::HandleFrob()oder operator neweine Ausnahme auslöst. In diesem Beispiel wird das Inkrement von m_NumberOfFrobsnicht zurückgesetzt. Daher wird jeder, der diese Instanz von verwendet Frobber, ein möglicherweise beschädigtes Objekt haben.

Dieses Beispiel mag dumm erscheinen (ok, ich musste mich ein wenig strecken, um eines zu konstruieren :-)), aber das Wichtigste ist, dass ein Programmierer nicht ständig an Ausnahmen denkt und dafür sorgt, dass jede Permutation des Zustands gerollt wird Zurück, wenn es Würfe gibt, geraten Sie auf diese Weise in Schwierigkeiten.

Als Beispiel können Sie sich das so vorstellen, wie Sie an Mutexe denken. In einem kritischen Abschnitt verlassen Sie sich auf mehrere Anweisungen, um sicherzustellen, dass Datenstrukturen nicht beschädigt werden und andere Threads Ihre Zwischenwerte nicht sehen können. Wenn eine dieser Aussagen nicht zufällig ausgeführt wird, geraten Sie in eine Welt voller Schmerzen. Nehmen Sie nun Sperren und Parallelität weg und überlegen Sie sich jede Methode so. Stellen Sie sich jede Methode als eine Transaktion von Permutationen für den Objektstatus vor, wenn Sie so wollen. Zu Beginn Ihres Methodenaufrufs sollte das Objekt einen sauberen Zustand haben, und am Ende sollte es auch einen sauberen Zustand geben. Dazwischen kann die Variable foonicht mit übereinstimmenbar, aber Ihr Code wird das irgendwann korrigieren. Ausnahmen bedeuten, dass jede Ihrer Aussagen Sie jederzeit unterbrechen kann. Bei jeder einzelnen Methode liegt es an Ihnen, es richtig zu machen und in diesem Fall einen Rollback durchzuführen oder Ihre Operationen so zu ordnen, dass Würfe keinen Einfluss auf den Objektstatus haben. Wenn Sie etwas falsch machen (und es ist leicht, diese Art von Fehler zu machen), sieht der Anrufer Ihre Zwischenwerte.

Methoden wie RAII, die C ++ - Programmierer gerne als ultimative Lösung für dieses Problem erwähnen, tragen wesentlich dazu bei, sich davor zu schützen. Aber sie sind keine Silberkugel. Es stellt sicher, dass Sie Ressourcen für einen Wurf freigeben, befreit Sie jedoch nicht davon, über eine Beschädigung des Objektstatus nachzudenken und Aufrufer, die Zwischenwerte sehen. Für viele Menschen ist es daher einfacher, mit Ausnahme des Codierungsstils keine Ausnahmen zu sagen . Wenn Sie die Art des Codes einschränken, den Sie schreiben, ist es schwieriger, diese Fehler einzuführen. Wenn Sie dies nicht tun, ist es ziemlich einfach, einen Fehler zu machen.

Es wurden ganze Bücher über ausnahmesichere Codierung in C ++ geschrieben. Viele Experten haben es falsch verstanden. Wenn es wirklich so komplex ist und so viele Nuancen hat, ist das vielleicht ein gutes Zeichen dafür, dass Sie diese Funktion ignorieren müssen. :-)

asveikau
quelle
9
Interessante Antwort, die jedoch nichts in meiner Programmiererfahrung widerspiegelt. Ich denke, es ist entweder kulturspezifisch (möglicherweise eher ein Problem in Java oder C ++ als beispielsweise Python) oder domänenspezifisch.
Ddaa
39
Ausnahmen, die in einer verwalteten Sprache unter Verwendung eines Try-Catch-finally-Musters geschrieben wurden, sollten niemals einen ungültigen Status hinterlassen, wenn sie ordnungsgemäß geschrieben wurden. Da die Ausführung des finally-Blocks garantiert ist, können Objekte dort freigegeben werden. Der Rest sollte durch Variablen erledigt werden, die außerhalb des Gültigkeitsbereichs und der Speicherbereinigung liegen.
Robert Harvey
7
@ddaa Das Problem ist in Python definitiv möglich. Das Ergebnis ist normalerweise ein schwer zu reproduzierender Fehler. Vielleicht waren Sie besonders akribisch oder hatten Glück. Aber dann haben Sie Recht, dass es eher ein Problem in C ++ ist, wo der häufigste Fehler von schlechtem EH ein Speicherverlust ist. Ich habe versucht zu betonen, dass Lecks nicht das schwerwiegendste Problem sind. @Robert GC verringert Speicherlecks, aber ich bin nicht sicher, ob verwalteter Code Sie von Programmiererfehlern befreit. Insbesondere wenn jemand nicht auf Ausnahmesicherheit achtet, weil er nicht glaubt, dass dies ein Problem in seiner Sprache ist, ist dies kein gutes Zeichen.
Asveikau
4
@lzprgmr gibt es sicherlich: Ausnahmen erlauben es Ihnen, mit diff umzugehen. Arten von Fehlern bei diff. Orte im Code. Die Behandlung eines Verbindungsfehlers erfordert möglicherweise eine erneute Verbindung, jedoch nicht mitten in einer tief verschachtelten Funktion. Sie möchten das an den Verbindungsmanager weiterleiten oder so. Wenn Sie sich dann mit Rückgabewerten befassen, müssen Sie die Fehler bei jedem einzelnen Anruf überprüfen und manuell aufblähen (im Fall eines Verbindungsrücksetzfehlers, z. B.). Außerdem stapeln sich die Rückgabewerte in verschachtelten Aufrufen: func3 kann -1 zurückgeben, func2 ruft func3 auf, gibt -2 bei seinen Fehlern zurück, -1 für func3 usw.
abourget
3
Ich habe abgelehnt, aber ich habe das umgekehrt, weil dies ein Grund ist, warum Ausnahmen abgelehnt werden. Meiner Meinung nach kann jedoch fast jede Methode oder jeder Code fehlschlagen. Sie können nicht jede Fehlerbedingung behandeln, indem Sie einen Rückgabewert dafür eingeben. Sie verlieren Informationen über den Fehler. Der Gedanke, dass Sie alles gut synchronisieren können, indem Sie jede einzelne Anweisung überprüfen und die Bereinigung durchführen, führt zu einem sehr komplizierten Code. Wenn Sie einen Fehler über mehrere Anweisungen hinweg abfangen und die eine oder zwei Ressourcen bereinigen, die nicht GC-geprüft sind, ist dies viel sauberer.
Maarten Bodewes
51

Der Grund dafür, dass Go keine Ausnahmen hat, wird in den häufig gestellten Fragen zum Go-Sprachdesign erläutert:

Ausnahmen sind eine ähnliche Geschichte. Es wurde eine Reihe von Entwürfen für Ausnahmen vorgeschlagen, die jedoch die Sprache und die Laufzeit erheblich komplexer machen. Ausnahmen umfassen naturgemäß Funktionen und vielleicht sogar Goroutinen; Sie haben weitreichende Auswirkungen. Es gibt auch Bedenken hinsichtlich der Auswirkungen, die sie auf die Bibliotheken haben würden. Sie sind per Definition außergewöhnlich, aber die Erfahrung mit anderen Sprachen, die sie unterstützen, zeigt, dass sie tiefgreifende Auswirkungen auf die Bibliotheks- und Schnittstellenspezifikation haben. Es wäre schön, ein Design zu finden, das es ihnen ermöglicht, wirklich außergewöhnlich zu sein, ohne häufige Fehler zu ermutigen, sich in einen speziellen Kontrollfluss zu verwandeln, den jeder Programmierer kompensieren muss.

Ausnahmen bleiben wie bei Generika ein offenes Thema.

Mit anderen Worten, sie haben noch nicht herausgefunden, wie Ausnahmen in Go auf eine Weise unterstützt werden können, die sie für zufriedenstellend halten. Sie sagen nicht, dass Ausnahmen per se schlecht sind ;

UPDATE - Mai 2012

Die Go-Designer sind jetzt vom Zaun heruntergeklettert. Ihre FAQ sagt jetzt Folgendes:

Wir glauben, dass das Koppeln von Ausnahmen an eine Kontrollstruktur, wie in der Try-Catch-Endlich-Sprache, zu verschlungenem Code führt. Außerdem werden Programmierer dazu ermutigt, zu viele normale Fehler, z. B. das Nichtöffnen einer Datei, als außergewöhnlich zu kennzeichnen.

Go verfolgt einen anderen Ansatz. Für eine einfache Fehlerbehandlung machen es die mehrwertigen Rückgaben von Go einfach, einen Fehler zu melden, ohne den Rückgabewert zu überladen. Ein kanonischer Fehlertyp in Verbindung mit den anderen Funktionen von Go macht die Fehlerbehandlung angenehm, unterscheidet sich jedoch erheblich von der in anderen Sprachen.

Go verfügt außerdem über einige integrierte Funktionen zum Signalisieren und Wiederherstellen von wirklich außergewöhnlichen Bedingungen. Der Wiederherstellungsmechanismus wird nur ausgeführt, wenn der Status einer Funktion nach einem Fehler heruntergefahren wird. Dies reicht aus, um eine Katastrophe zu bewältigen, erfordert jedoch keine zusätzlichen Kontrollstrukturen und kann bei guter Verwendung zu einem sauberen Fehlerbehandlungscode führen.

Weitere Informationen finden Sie im Artikel Aufschieben, Panik und Wiederherstellen.

Die kurze Antwort lautet also, dass sie es mit der mehrwertigen Rückgabe anders machen können. (Und sie haben sowieso eine Form der Ausnahmebehandlung.)


... und Linus von Linux Ruhm hat Ausnahmen Mist genannt.

Wenn Sie wissen möchten, warum Linus Ausnahmen für Mist hält, ist es am besten, nach seinen Schriften zu diesem Thema zu suchen. Das einzige, was ich bisher aufgespürt habe, ist dieses Zitat, das in ein paar E-Mails unter C ++ eingebettet ist :

"Die ganze Sache mit der Behandlung von C ++ - Ausnahmen ist grundlegend kaputt. Sie ist besonders für Kernel kaputt."

Sie werden feststellen, dass es sich insbesondere um C ++ - Ausnahmen handelt und nicht um Ausnahmen im Allgemeinen. (Und C ++ - Ausnahmen haben anscheinend einige Probleme, die es schwierig machen, sie richtig zu verwenden.)

Mein Fazit ist, dass Linus Ausnahmen (im Allgemeinen) überhaupt nicht "Mist" genannt hat!

Stephen C.
quelle
30
Ich hasse es, wenn sie Informationen verstecken, indem sie sie in die FAQ aufnehmen. :)
Brian D Foy
7
Beachten Sie, dass Linus diese E-Mail mit "C ++ ist eine schreckliche Sprache" startet. und schimpft weiter darüber, wie sehr er sowohl C ++ als auch Leute hasst, die sich dafür entscheiden, darin zu programmieren. Folglich denke ich nicht, dass seine Meinung zu den Ausnahmen von C ++ angesichts seiner etwas voreingenommenen Meinung zu C ++ als zuverlässig angesehen werden kann.
Pharap
1
@ Hi-Angel - Wie der von mir zitierte Text sagt: "Für eine einfache Fehlerbehandlung machen es die mehrwertigen Rückgaben von Go einfach, einen Fehler zu melden, ohne den Rückgabewert zu überladen." . So hängt es zusammen. In jedem Fall zitiere ich die Gründe der Go-Designer. Wenn Sie streiten möchten, argumentieren Sie mit >> ihnen <<.
Stephen C
1
@ Hi-Angel - Ich habe diese Absätze nicht geschrieben. Ich habe sie nur zitiert. Wenn Sie ein Problem mit ihnen haben, sollten Sie es wahrscheinlich mit den Autoren besprechen. Theoretisch hätte ich ein Tutorial zur Go-Sprache als Kontext bereitstellen können. Um ehrlich zu sein, können Leute, die die Go-Terminologie nicht verstehen, die Go-Website besuchen, um herauszufinden, was das alles bedeutet.
Stephen C
1
".. führt zu verschlungenem Code" Vor langer Zeit habe ich ein C-Programm mit vielen Zeichenfolgenoperationen geschrieben. Bei jeder Methode wurde Speicher zugewiesen und anschließend überprüft, ob die Zuordnung erfolgreich war. Es stellte sich heraus, dass der Großteil des Codes nur die Zuordnungen überprüfte. Ist es nicht verworren? C ++ war mit Ausnahmen eine große Rettung für mich.
Robsosno
29

Ausnahmen sind an sich nicht schlecht, aber wenn Sie wissen, dass sie häufig auftreten werden, können sie in Bezug auf die Leistung teuer sein.

Als Faustregel gilt, dass Ausnahmen außergewöhnliche Bedingungen kennzeichnen sollten und dass Sie sie nicht zur Steuerung des Programmflusses verwenden sollten.

Robert Harvey
quelle
9
@ Robert: "Sie sollten sie nicht zur Steuerung des Programmflusses verwenden", ich habe nicht so darüber nachgedacht, neue Perspektive für mich: P +1
okw
2
Es kommt auch wirklich auf die Sprache an. Es ist schwierig, Ausnahmen zu vermeiden, wenn Sie beispielsweise in Java programmieren.
Charles Salvia
2
@ Charles: Ich denke, der Punkt ist, dass Ausnahmen in Situationen angemessen sind, die auf einen Fehler, ein falsch konfiguriertes System oder unangemessene Eingaben hinweisen. Die meisten Ausnahmen der Java-Bibliothek können im Code "Normaler Workflow" vermieden werden.
Artelius
6
Sie müssen nicht viel kosten. Sie können beispielsweise einen "Versuch" implementieren, der keine Ausführungszeit kostet, und Ausnahmebehandlungsroutinen in einer Tabelle "werfen" lassen, basierend auf den Aufruferadressen, die auf dem Stapel angezeigt werden ... Ich würde sagen, dass die größten Gründe dies nicht tun Nutzungsausnahmen beziehen sich überhaupt nicht auf die Leistung.
Asveikau
Umformuliert; Die Frage deutet eindeutig darauf hin, dass Ausnahmen im Allgemeinen oder überhaupt keine Ausnahmen verwendet werden (sie sind Mist oder nicht einmal in der Sprache). Ihre Antwort zeigt nur, warum Ausnahmen für die Leistung schlecht sind, wenn sie für den Programmsteuerungsfluss verwendet werden.
Maarten Bodewes
26

Ich bin nicht einverstanden mit "nur in einer Ausnahmesituation Ausnahmen werfen". Während im Allgemeinen wahr, ist es irreführend. Ausnahmen sind Fehlerbedingungen (Ausführungsfehler).

Unabhängig von der verwendeten Sprache erhalten Sie eine Kopie der Framework Design Guidelines : Konventionen, Redewendungen und Muster für wiederverwendbare .NET-Bibliotheken (2. Ausgabe). Das Kapitel über das Auslösen von Ausnahmen ist ohne Peer. Einige Zitate aus der ersten Ausgabe (die zweite bei meiner Arbeit):

  • KEINE Fehlercodes zurückgeben.
  • Fehlercodes können leicht ignoriert werden und sind es häufig.
  • Ausnahmen sind das primäre Mittel zum Melden von Fehlern in Frameworks.
  • Eine gute Faustregel lautet: Wenn eine Methode nicht das tut, was ihr Name andeutet, sollte sie als Fehler auf Methodenebene betrachtet werden, was zu einer Ausnahme führt.
  • Verwenden Sie nach Möglichkeit KEINE Ausnahmen für den normalen Kontrollfluss.

Es gibt Seiten mit Hinweisen zu den Vorteilen von Ausnahmen (API-Konsistenz, Auswahl des Speicherorts des Fehlerbehandlungscodes, verbesserte Robustheit usw.). Es gibt einen Abschnitt zur Leistung, der mehrere Muster enthält (Tester-Doer, Try-Parse).

Ausnahmen und Ausnahmebehandlung sind nicht schlecht. Wie jede andere Funktion können sie missbraucht werden.

TrueWill
quelle
3
Da muss ich nicht zustimmen. Ich bin nicht gegen Ausnahmen, und dieses Buch ist ein Muss, aber es ist voreingenommen in Richtung .NET-Entwicklung und C #.
3
Ich weiß, dass dies uralt ist, wollte nur kommentieren, dass es anscheinend eine allgemeine Meinungsverschiedenheit zwischen dem .NET-Typ und dem * nix-Typ gibt. Alle Bibliotheken, die ich als Linux-Entwickler verwendet habe, verwenden Rückkehrcodes, und * nix-Styleguides, die ich gelesen habe (wie zum Beispiel die meines Unternehmens und von Google ), sagen einfach "Wir machen keine Ausnahmen". Ich finde es einfach interessant.
Jarvisteve
1
Frameworks sollten Ausnahmen anders behandeln als Endbenutzeranwendungen. Frameworks haben keine andere Möglichkeit, mit Fehlern umzugehen, als eine Ausnahme auszulösen, wie dies bei Consumer-Anwendungen der Fall ist.
0x6C38
11

Aus der Sicht von Golang hält das Fehlen einer Ausnahmebehandlung den Kompilierungsprozess einfach und sicher.

Aus der Sicht von Linus verstehe ich, dass es beim Kernel-Code ALLES um Eckfälle geht. Es ist also sinnvoll, Ausnahmen abzulehnen.

Ausnahmen sind im Code sinnvoll, wenn es in Ordnung ist, die aktuelle Aufgabe auf den Boden zu legen, und wenn allgemeiner Fallcode wichtiger ist als die Fehlerbehandlung. Sie erfordern jedoch die Codegenerierung vom Compiler.

Zum Beispiel sind sie in den meisten übergeordneten, benutzerbezogenen Codes wie Web- und Desktop-Anwendungscode in Ordnung.

ddaa
quelle
Was für Kernel-Code gilt, gilt jedoch auch für lange laufende native Serverprozesse.
Lothar
11

Ausnahmen an und für sich sind nicht "schlecht", es ist die Art und Weise, wie Ausnahmen manchmal behandelt werden, die dazu neigt, schlecht zu sein. Bei der Behandlung von Ausnahmen können verschiedene Richtlinien angewendet werden, um einige dieser Probleme zu beheben. Einige davon sind (ohne darauf beschränkt zu sein):

  1. Verwenden Sie keine Ausnahmen, um den Programmfluss zu steuern - dh verlassen Sie sich nicht auf "catch" -Anweisungen, um den Logikfluss zu ändern. Dies verbirgt nicht nur verschiedene Details in der Logik, sondern kann auch zu einer schlechten Leistung führen.
  2. Werfen Sie keine Ausnahmen aus einer Funktion heraus, wenn ein zurückgegebener "Status" sinnvoller wäre - werfen Sie Ausnahmen nur in einer Ausnahmesituation. Das Erstellen von Ausnahmen ist eine teure, leistungsintensive Operation. Wenn Sie beispielsweise eine Methode zum Öffnen einer Datei aufrufen und diese Datei nicht vorhanden ist, lösen Sie eine "FileNotFound" -Ausnahme aus. Wenn Sie eine Methode aufrufen, die bestimmt, ob ein Kundenkonto vorhanden ist, geben Sie einen booleschen Wert zurück und geben Sie keine "CustomerNotFound" -Ausnahme zurück.
  3. Verwenden Sie beim Festlegen, ob eine Ausnahme behandelt werden soll, keine "try ... catch" -Klausel, es sei denn, Sie können mit der Ausnahme etwas Nützliches tun. Wenn Sie die Ausnahme nicht behandeln können, sollten Sie sie einfach den Aufrufstapel aufblasen lassen. Andernfalls werden Ausnahmen möglicherweise vom Handler "verschluckt" und die Details gehen verloren (es sei denn, Sie werfen die Ausnahme erneut).
Jeff Bramwell
quelle
2
Die Rückgabe des Status ist eine schwierige Sache. Ich habe viel zu viel Code gesehen, der eine GetCustomer-Methode enthält, die eine Kundenentität bei Erfolg oder null bei einem Fehler zurückgibt. In mehreren Fällen hat der aufrufende Code das Ergebnis nie überprüft, sondern sofort auf den Kunden zugegriffen. Dies funktionierte die meiste Zeit ...
TrueWill
3
Wenn GetCustomer jedoch eine Ausnahme auslöst, anstatt null zurückzugeben, muss der Clientcode die Ausnahme weiterhin behandeln. Ob durch Überprüfen auf Null oder durch Behandeln von Ausnahmen, die Verantwortung liegt beim Client-Code - wenn er die Dinge nicht richtig macht, explodiert früher oder später etwas.
Chris
1
@TrueWill Sprachen, die Vorlagen / Generika unterstützen, lösen dieses Problem, indem sie Option<T>anstelle von nullheutzutage ein zurückgeben. Ich bin gerade in Java 8 eingeführt worden und habe einen Hinweis von Guava (und anderen) erhalten.
Maarten Bodewes
@owlstead Ja. Ich liebe die vielleicht Monade. Dies ist ein guter Weg, wenn Ihre Sprache dies unterstützt und Mustervergleiche anbietet.
TrueWill
@owlstead Auch hier gilt das, was Chris gesagt hat, immer noch als stark - der Benutzer muss daran denken, die Funktion .orElse (defaultObject) aufzurufen oder welche Sprache auch immer die betreffende Sprache gewählt hat. Letztendlich sind letztendlich die Programmierer das Problem und nicht die Fehlerbehandlungsmethode.
Pharap
9

Typische Argumente sind, dass es keine Möglichkeit gibt zu sagen, welche Ausnahmen aus einem bestimmten Code herauskommen (abhängig von der Sprache), und dass sie zu sehr wie gotos sind, was es schwierig macht, die Ausführung mental zu verfolgen.

http://www.joelonsoftware.com/items/2003/10/13.html

In dieser Frage besteht definitiv kein Konsens. Ich würde sagen, dass aus Sicht eines Hardcore-C-Programmierers wie Linus Ausnahmen definitiv eine schlechte Idee sind. Ein typischer Java-Programmierer befindet sich jedoch in einer völlig anderen Situation.

Tim Sylvester
quelle
1
C-Code hat Ausnahmen, nur auf eine andere Art und Weise. Sie müssen jeden Aufruf einer nicht trivialen Funktion in ifs einschließen, was die Verwendung dieser Sprache zu Kopfschmerzen macht!
RCIX
1
Es gibt auch das setjmp/ longjmpZeug, was ziemlich schlecht ist.
Tim Sylvester
9
Möchten Sie wirklich den Rat eines Mannes befolgen, der Duct Tape-Programmierer schätzt und der nicht glaubt, dass Unit-Tests notwendig sind? joelonsoftware.com/items/2009/09/23.html
TrueWill
4
Dies ist ein klassischer Fehler (oder Betrug) in einer Diskussion, bei der Argumente zu diesem Thema durch Persönlichkeitsreferenzen ersetzt werden. Das ist normalerweise ein Zeichen für eine degenerierende Diskussion.
Petr Gladkikh
1
@PetrGladkikh Die Diskussion begann mit dem OP unter Bezugnahme auf Linus 'Meinung ... dass Betrug als Trugschluss des Appells an die Autorität bekannt ist. Die Diskussion kann von dort aus nur bergauf gehen, und es ist kein "Betrug", die Frage zu beantworten, warum Linus Ausnahmen nicht mag, indem er sich auf seine Persönlichkeit bezieht.
Jim Balter
7

Ausnahmen sind nicht schlecht. Sie passen gut zum RAII-Modell von C ++, was das eleganteste an C ++ ist. Wenn Sie bereits eine Menge Code haben, der nicht ausnahmesicher ist, sind sie in diesem Zusammenhang schlecht. Wenn Sie wirklich Low-Level-Software wie das Linux-Betriebssystem schreiben, sind sie schlecht. Wenn Sie Ihren Code gerne mit einer Reihe von Fehlerrückgabeprüfungen verunreinigen, sind diese nicht hilfreich. Wenn Sie keinen Plan für die Ressourcensteuerung haben, wenn eine Ausnahme ausgelöst wird (die von C ++ - Destruktoren bereitgestellt wird), sind sie fehlerhaft.

paul
quelle
7
RAII ist auch ohne Ausnahmen nützlich.
Mark Ransom
4
Ausnahmen sind jedoch ohne RAII (oder eine andere automatische Ressourcenverwaltung) nicht sinnvoll.
Greg Rogers
+1 für den Hinweis auf Situationen, in denen Ausnahmen nicht angemessen sind und Ausnahmen nicht von Natur aus schlecht sind.
Pharap
4

Ein guter Anwendungsfall für Ausnahmen ist also ....

Angenommen, Sie befinden sich in einem Projekt und jeder Controller (etwa 20 verschiedene Hauptcontroller) erweitert einen einzelnen Superklassen-Controller um eine Aktionsmethode. Dann macht jeder Controller eine Reihe von Dingen, die sich voneinander unterscheiden, und ruft in einem Fall die Objekte B, C, D und in einem anderen Fall F, G, D auf. Ausnahmen kommen hier in vielen Fällen zur Rettung, in denen es Tonnen von Rückkehrcodes gab und JEDER Controller anders damit umging. Ich habe den ganzen Code verprügelt, die richtige Ausnahme von "D" geworfen, ihn in der Superklassen-Controller-Aktionsmethode abgefangen und jetzt sind alle unsere Controller konsistent. Zuvor gab D für MEHRERE verschiedene Fehlerfälle null zurück, über die wir dem Endbenutzer Bescheid geben möchten, dies aber nicht konnten, und ich habe es nicht getan.

Ja, wir müssen uns um jede Ebene und alle Ressourcenbereinigungen / -lecks kümmern, aber im Allgemeinen hatte keiner unserer Controller Ressourcen, nach denen er bereinigen konnte.

Gott sei Dank hatten wir Ausnahmen, sonst hätte ich einen riesigen Refactor bekommen und zu viel Zeit mit etwas verschwendet, das ein einfaches Programmierproblem sein sollte.

Dean Hiller
quelle
1
+1 Leicht eines der besten Argumente für die Verwendung von Ausnahmen, die ich gelesen habe. Hätte detailliertere Beispiele verwenden können (z. B. ein UML-Diagramm, einen Pseudocode oder einen tatsächlichen Code), aber der Punkt, an dem Unterklassen eine konsistente Leistung erzielen sollen, ist gut. Die Tatsache, dass Ihre Beweise anekdotisch sind, zeigt auch, dass Ausnahmen in realen Situationen nützlich sind und die Nützlichkeit der Hauptzweck jeder Sprachfunktion ist.
Pharap
Wenn Sie sich in einer Scala befinden, können Sie stattdessen Try [ResponseType] zurückgeben, das eine Ausnahme oder eine tatsächliche Antwort darstellt. Sie können dann dem gleichen Muster folgen, dem ich mich oben entzogen habe, ohne tatsächliche Ausnahmen, außer denen, die in den Versuch aufgenommen wurden. Dann ist es so, als ob jede Methode, die Sie haben, 1 + n Antworttypen zurückgibt, die ich für notwendig halte. Wir geben jedoch in scala Future [response] zurück, die ähnlich wie Try funktionieren, aber bei der asynchronen Programmierung helfen können.
Dean Hiller
2

Theoretisch sind sie wirklich schlecht. In einer perfekten mathematischen Welt kann es keine Ausnahmesituationen geben. Schauen Sie sich die funktionalen Sprachen an, sie haben keine Nebenwirkungen, so dass sie praktisch keine Quelle für außergewöhnliche Situationen haben.

Aber die Realität ist eine andere Geschichte. Wir haben immer Situationen, die "unerwartet" sind. Deshalb brauchen wir Ausnahmen.

Ich denke, wir können uns Ausnahmen als Syntaxzucker für ExceptionSituationObserver vorstellen. Sie erhalten nur Benachrichtigungen über Ausnahmen. Nichts mehr.

Ich denke, mit Go werden sie etwas einführen, das sich mit "unerwarteten" Situationen befasst. Ich kann mir vorstellen, dass sie versuchen werden, es als Ausnahmen weniger destruktiv und mehr als Anwendungslogik klingen zu lassen. Aber das ist nur meine Vermutung.

Mike Chaliy
quelle
2
"Schauen Sie sich die funktionalen Sprachen an, sie haben keine Nebenwirkungen, so dass sie praktisch keine Quelle für außergewöhnliche Situationen haben." Das ist eine grobe Übertreibung.
Stephen C
3
Was ist 5/0 in Mathe? Arcsin (200)? Sqrt (-1)? Mathe hat viele Ausnahmesituationen.
Robert Fraser
3
Dies sind keine Ausführungssituationen ... sie haben einfach keine Bedeutung ... und könnten daher als Ausnahmen implementiert werden ... sondern könnten auch als Vialationen von Voraussetzungen implementiert werden. Dies hängt also von der technischen Implementierung ab.
Mike Chaliy
3
@ MikeChaliy - Es tut mir leid, aber das ist nur Sophistik. Sie können diese Art von Argumentation anwenden, um zu sagen, dass es NIEMALS Ausnahmesituationen in irgendetwas gibt. In Wirklichkeit sind mathematische Ausdrücke, die keine Bedeutung haben (oder keinen bestimmten Wert haben), außergewöhnlich. Dies bedeutet nicht, dass sie durch Auslösen und Abfangen von Ausnahmen behandelt werden müssen. Wenn Sie dies jedoch nicht tun, benötigen Sie entweder spezielle Werte (wie Inf und Nan) oder Operationen, die mehrere Werte zurückgeben. Kurz gesagt, diese Fälle erfordern eine spezielle Behandlung.
Stephen C
1
Computer sind Zustandsmaschinen. Keine perfekte Mathe-Welt.
Arunav Sanyal
1

Das Ausnahmebehandlungsparadigma von C ++, das eine Teilbasis für das von Java und wiederum .net bildet, führt einige gute Konzepte ein, weist jedoch auch einige schwerwiegende Einschränkungen auf. Eine der wichtigsten Entwurfsabsichten der Ausnahmebehandlung besteht darin, Methoden zu ermöglichen, sicherzustellen, dass sie entweder ihre Nachbedingungen erfüllen oder eine Ausnahme auslösen, und sicherzustellen, dass alle Bereinigungen durchgeführt werden, die erforderlich sind, bevor eine Methode beendet werden kann. Leider bieten die Ausnahmebehandlungsparadigmen von C ++, Java und .net keine gute Möglichkeit, die Situation zu behandeln, in der unerwartete Faktoren die erwartete Bereinigung verhindern. Dies bedeutet wiederum, dass man entweder riskieren muss, dass alles zum Stillstand kommt, wenn etwas Unerwartetes passiert (der C ++ - Ansatz zur Behandlung einer Ausnahme tritt beim Abwickeln des Stapels auf).

Selbst wenn die Ausnahmebehandlung im Allgemeinen gut wäre, ist es nicht unangemessen, ein Ausnahmebehandlungsparadigma als inakzeptabel anzusehen, das kein gutes Mittel zur Behandlung von Problemen darstellt, die beim Aufräumen nach anderen Problemen auftreten. Das heißt nicht, dass ein Framework nicht mit einem Ausnahmebehandlungsparadigma entworfen werden kann, das selbst in Szenarien mit mehreren Fehlern ein vernünftiges Verhalten gewährleisten kann, aber noch keine der Top-Sprachen oder Frameworks kann dies.

Superkatze
quelle
1

Ich habe nicht alle anderen Antworten gelesen, daher wurde dies bereits erwähnt, aber ein Kritikpunkt ist, dass Programme in langen Ketten brechen, was es schwierig macht, Fehler beim Debuggen des Codes aufzuspüren. Wenn Foo () beispielsweise Bar () aufruft, das Wah () aufruft, das ToString () aufruft, sieht das versehentliche Verschieben der falschen Daten in ToString () wie ein Fehler in Foo () aus, eine fast völlig unabhängige Funktion.

kingfrito_5005
quelle
0
  • Eine Ausnahme, die nicht behandelt wird, ist im Allgemeinen schlecht.
  • Eine schlecht behandelte Ausnahme ist (natürlich) schlecht.
  • Die "Güte / Schlechtigkeit" der Ausnahmebehandlung hängt vom Kontext / Umfang und der Angemessenheit ab und nicht, um dies zu tun.
OK W
quelle
0

Okay, langweilige Antwort hier. Ich denke, es hängt wirklich von der Sprache ab. Wenn eine Ausnahme zugewiesene Ressourcen zurücklassen kann, sollten sie vermieden werden. In Skriptsprachen verlassen sie nur Teile des Anwendungsflusses oder überspringen sie. Das ist an sich unangenehm, aber es ist eine akzeptable Idee, mit Ausnahmen fast fatalen Fehlern zu entkommen.

Für die Fehlersignalisierung bevorzuge ich generell Fehlersignale. Alles hängt von der API, dem Anwendungsfall und dem Schweregrad ab oder davon, ob die Protokollierung ausreicht. Außerdem versuche ich das Verhalten neu zu definieren und throw Phonebooks()stattdessen. Die Idee ist, dass "Ausnahmen" oft Sackgassen sind, aber ein "Telefonbuch" hilfreiche Informationen zur Fehlerbehebung oder zu alternativen Ausführungsrouten enthält. (Noch kein guter Anwendungsfall gefunden, aber versuchen Sie es weiter.)

Mario
quelle
0

Für mich ist das Problem sehr einfach. Viele Programmierer verwenden den Ausnahmebehandler unangemessen. Mehr Sprachressourcen sind besser. Mit Ausnahmen umgehen zu können ist gut. Ein Beispiel für eine schlechte Verwendung ist ein Wert, der eine Ganzzahl sein muss, die nicht überprüft werden muss, oder eine andere Eingabe, die sich teilen und nicht auf eine Teilung von Null prüfen kann. Die Ausnahmebehandlung kann ein einfacher Weg sein, um mehr Arbeit und hartes Denken zu vermeiden, so der Programmierer Möglicherweise möchten Sie eine fehlerhafte Verknüpfung erstellen und eine Ausnahmebehandlung anwenden ... Die Aussage: "Ein professioneller Code schlägt NIEMALS fehl" kann illusorisch sein, wenn einige der vom Algorithmus verarbeiteten Probleme von Natur aus ungewiss sind. Vielleicht ist in den unbekannten Situationen von Natur aus gut der Ausnahmebehandler ins Spiel gekommen. Gute Programmierpraktiken sind umstritten.

iuri
quelle
Das Problem ist nicht (oder sollte es nicht sein), ob Code fehlschlagen kann - ein größeres Problem ist das Ausmaß, in dem man sich um die Einzelheiten kümmert, wenn der Code fehlschlägt. Wenn man versucht, ein Dokument zu laden und eine der "Daten lesen" -Methoden fehlschlägt, ist es einem oft egal, welche, da der Effekt unabhängig davon gleich ist: Das Dokument kann nicht geladen werden. Konzeptionell sollte die Ausnahmebehandlung dafür gut sein. Das Problem ist, dass die Ausnahmebehandlungsparadigmen von .NET und Java keine gute Möglichkeit bieten, "langweilige" Ausnahmen, die zusammengefasst werden sollten, von solchen zu unterscheiden, die nicht zusammengefasst werden sollten.
Supercat