Warum ist Option / Vielleicht eine gute Idee und geprüfte Ausnahmen nicht?

23

Einige Programmiersprachen wie zB Scala haben das Konzept von OptionTypen (auch als Maybe), die entweder einen Wert enthalten können oder nicht.

Nach dem, was ich über sie gelesen habe, werden sie allgemein als überlegene Lösung für dieses Problem angesehen null, da sie den Programmierer ausdrücklich dazu zwingen, die Fälle zu berücksichtigen, in denen es möglicherweise keinen Wert gibt, anstatt nur zur Laufzeit in die Luft zu jagen.

Checked Exceptions in Java scheinen dagegen eine schlechte Idee zu sein, und Java scheint die einzige weit verbreitete Sprache zu sein, die sie implementiert. Die Idee, die dahinter steckt, ähnelt der Idee Option, den Programmierer explizit zu zwingen, sich mit der Tatsache auseinanderzusetzen, dass eine Ausnahme ausgelöst werden könnte.

Gibt es zusätzliche Probleme mit aktivierten Ausnahmen, die OptionTypen nicht haben? Oder sind diese Ideen nicht so ähnlich, wie ich denke, und es gibt gute Gründe, die explizite Behandlung für Optionen und nicht für Ausnahmen zu erzwingen?

Verrückter Wissenschaftler
quelle
Siehe auch den Either e aDatentyp.
4
Über geprüfte Ausnahmen: Als Benutzer einer Vielzahl von Open-Source- und internen Java-Bibliotheken mit sich entwickelnder Codebasis und fehlenden / veralteten Dokumenten schaudere ich bei dem Gedanken, dass Java bestimmte explizit zu deklarierende Ausnahmen nicht erzwingen würde. Es wäre ein Albtraum von unbehandelten Laufzeitfehlern, die unerwartet an schlechten Orten auftauchten. Und mit Java7 wird die Ausnahmebehandlung endlich nahezu normal, da ein Großteil der alten Versuchsfalle beseitigt wird.
Hyde

Antworten:

24

Weil Options zusammensetzbar sind. Es gibt viele nützliche Methoden Option, mit denen Sie kurze Code zu schreiben, während immer noch eine genaue Kontrolle über die Strömung erlaubt: map, flatMap, toList, flattenund vieles mehr. Dies liegt an der Tatsache, dass Optiones sich um eine bestimmte Art von Monade handelt, einige Objekte, die wir sehr gut komponieren können. Hätten Sie diese Methoden nicht und müssten die Mustererkennung immer aktivieren Optionoder isDefinedhäufig aufrufen , wären sie bei weitem nicht so nützlich.

Während aktivierte Ausnahmen die Sicherheit erhöhen, gibt es nichts, was Sie mit ihnen tun können, außer sie zu fangen oder sie den Stapel in die Luft sprudeln zu lassen (mit dem hinzugefügten Boilerplate in der Typdeklaration).

Andrea
quelle
1
Überprüfte Ausnahmen setzen sich mehr oder weniger auf die gleiche Weise zusammen ... Der Unterschied zwischen try {/* bunch of complex code involving calls to 50 different methods that may throw SomeCheckedException */} catch(SomeCheckedException e) {/* operation failed, do something */}und fromMaybe someDefaultValue (something >>= otherThing >>= ...50 other functions that may return Nothing...)ist was genau? Abgesehen von der Tatsache, dass Ersteres mehr Details darüber liefert, was schief gelaufen ist.
user253751
14

Ausnahmen und Vielleicht-Objekte befassen sich nicht mit der gleichen Art von Problemen, obwohl sie miteinander verbunden sind.

Ausnahmen

Ausnahmen leuchten wirklich, wenn Sie sich nicht vor Ort mit einer Ausnahmesituation auseinandersetzen müssen (die in einigen Fällen ein Fehler ist). Sie analysieren beispielsweise eine CSV-Datei und möchten sich vor Zeilen mit falscher Formatierung schützen. Die Stelle, an der Sie feststellen, dass etwas nicht stimmt, können einige Funktionsaufrufe außerhalb der Zeileniteration sein. Wenn Sie eine Ausnahme auf der tiefsten Ebene auslösen (wo Sie Informationen zum Formatierungsproblem erhalten), können Sie diese in der Schleife abfangen, den Fehler protokollieren und mit der nächsten Zeile fortfahren. Sie müssen im Rest des Codes nichts ändern.

Die aktivierte Ausnahme fügt viel Schmerz hinzu, da alle Zwischenfunktionen den Typ throwable deklarieren müssen. Die Funktion hat den ursprünglichen Zweck verfehlt, weshalb sie heutzutage nicht beliebt ist.

Vielleicht Gegenstände

Möglicherweise sollten Objekte ausgewählt werden, wenn Sie in der Lage sind, mit einem "Fehler" vor Ort umzugehen. In diesem Sinne sind sie ein Ersatz für einen Rückkehrcode + Pass-by-Referenz-API oder einen nullfähigen Typ.

Der Vorteil des Objekts "Vielleicht" besteht darin, dass Sie explizit erklären, dass möglicherweise etwas nicht stimmt. In haskell muss ein Nicht-Vielleicht-Objekt einen Wert haben, sonst wird das Programm nicht kompiliert.

Das Problem bei nullfähigen Typen ist, dass Sie die ganze Zeit auf null prüfen müssen, um absolut sicher zu sein. Der Status "Möglicherweise stimmt etwas nicht" ist der Standardstatus.

Das Problem mit Returncodes + Pass von ref apis ist, dass sie für die meisten Menschen weniger lesbar sind.

Simon Bergot
quelle
1
@MattFenwick danke für das Feedback. Warum macht das CSV-Beispiel Ihrer Meinung nach keinen Sinn? Das OP fragt nicht wirklich nach Techniken zum Vermeiden von Boilerplates, und ich habe das Gefühl, dass Vokabeln wie applikative Funktoren und Monaden für diese Frage zu technisch sind.
Simon Bergot
1
Ich möchte darauf hinweisen, dass IDEs mit Java (nicht sicher von anderen Sprachen mit geprüften Ausnahmen) das Hinzufügen und Beschneiden von Throws und das Aktualisieren des Java-Kommentarteils übernehmen. Zumindest ist dieser Teil also keine Mühe und sicherlich kein Schmerz. Ob es ein Schmerz oder ein Segen oder etwas dazwischen ist, wenn Sie API-Design machen, das ist eine andere Sache ...
Hyde
5
@hyde: Nur weil eine IDE die Erzeugung von sinnlosen Boilerplates automatisieren kann, bedeutet dies nicht, dass sinnlose Boilerplates kein Problem sind.
Michael Shaw
2
@hyde: Aber der Schmerz wird nicht beseitigt. Die sinnlose Kesselplatte ist immer noch da und wirft den Code ohne Grund durcheinander. Wenn es einen Grund für das Boilerplate gibt, was ist es?
Michael Shaw
2
@MichaelShaw Wenn eine Ausnahme sinnlos ist, entfernen Sie sie: Ignorieren Sie die Situation, oder geben Sie stattdessen einen Fehlerwert zurück. Wenn es sich um einen Fehler oder eine nicht behebbare Situation handelt: Verwenden Sie eine ungeprüfte Ausnahme. Was bleibt, ist genauso wichtig wie zum Beispiel die Art der Parameter, nicht das sinnlose Boilerplate. Wenn es sich bei der vorhandenen Bibliothek um eine fehlerhafte API handelt, ziehen Sie eine Wrapper-Methode / -Klasse in Betracht, die eine andere Bibliothek verwendet, oder leiden nur unter der fehlerhaften API.
Hyde
1

Denn mit können MaybeSie die Behandlung des Fehlers verzögern, bis Sie den Wert tatsächlich benötigen (was einige Methodenaufrufe entfernt sein kann).

Die aktivierte Ausnahme muss am Anrufort behandelt werden

Die einzige Ausnahme besteht darin, dass mehr Informationen darüber weitergegeben werden können, warum dies fehlgeschlagen ist (es sei denn, jemand entwickelt MaybeErrorim Fehlerfall eine mit einem Wurffeld).

Ratschenfreak
quelle
2
Aber ich kann die Behandlung der geprüften Ausnahme verschieben, indem ich erkläre, dass meine Methode diese Ausnahme auslöst.
Mad Scientist
1
@ MadScientist, die nur geht den Call-Stack, während Vielleicht kann in alle Richtungen gehen
Ratschenfreak
5
Ich denke, Sie sollten MaybeTypen nicht mit Fehlern beim Umgang verwechseln . Eine Ausnahme wird verwendet, um einen Fehler zu melden, ein Optionstyp wird verwendet, um das Ergebnis einer Teilfunktion darzustellen. Eine teilweise Funktionsrückgabe Nothingist kein Fehler.
Giorgio
@MadScientist: Wenn ein Methodenaufruf eine "Ungültiger Wert" -Anzeige zurückgibt, kann die Anweisung unmittelbar danach ausgeführt werden. Im Gegensatz dazu wird die Anweisung nach dem Aufruf übersprungen, wenn eine Methode eine Ausnahme auslöst, die nicht sofort abgefangen wird. Das Durchsickernlassen von geprüften Ausnahmen im Aufrufstapel ist im Allgemeinen schlecht (und hätte nicht die einfachste Möglichkeit sein sollen, mit ihnen umzugehen), da ein Aufrufer nicht erkennen kann, ob die Bedingung die von der aufgerufenen Methode erwartete Bedeutung hat, oder ob es sich um eine unerwartete Bedingung handelt, die die aufgerufene Methode in die Luft sprudeln lässt.
Supercat