Assertions sind abschaltbare Exceptions, die in der Regel dazu gedacht sind, Programmierfehler zu finden, keine Anwenderfehler. Bei der normalen Benutzung werden sie in der Regel deaktiviert.
Vor kurzem war ich wieder an einem Punkt, an dem ich aufgrund fehlender Erfahrung nicht weiterwusste und musste mir Meinungen einholen. Das Thema war Fehlerbehandlung, oder genauer Exceptions. Wie man Exceptions auslöst, einfängt, etc. weiß jeder, das ist Syntaxkram und Referenzmaterial dazu findet man an jeder Ecke. Was mir teilweise Kopfzerbrechen bereitet hat, war, dass ich realisierte nicht wirklich zu wissen wie man Exceptions sinngemäß einsetzt. Nach stundenlangen Recherchen im Internet war ich zwar um eine Vielzahl an Meinungen, was Exceptions sind, wozu sie gedacht sind und wie man sie am besten einsetzt, schlauer, aber so richtig sinnvoll empfand ich keine davon. Schließlich bin ich über diesen Artikel gestolpert, in dem noch die letzten, für mich noch fehlenden Aspekte deutlich hervorgehoben waren.
Wie ist es eigentlich bei euch? Bevorzugt ihr Fehlercodes? Exceptions? Assertions? Mit welcher Begründung? Und falls ihr euch nicht vor Exceptions scheut, wie sieht eure Strategie dazu aus?
Kann ich schwer sagen. Ich war mal sehr prozedural und kannte daher gar keine Exceptions (die sind doch OOP-only, oder?). Inzwischen benutze ich hauptsächlich Java (Studium) und bin daher zumindest mit den von Java selbst geworfenen Exceptions konfrontiert, die ich meistens aber gar nicht fange, weil ich auch nur irgendwelche Methoden implementiere, die dann mit falschem Input gefüttert wurden und die Exception daher ruhig den Caller erreichen soll - ich könnte sie höchstens noch in eine eigene Exception wrappen, aber was bringt das?
Ich finde das Konzept von Exceptions eigentlich sehr sinnvoll, auch wenn ich sie wenig nutze. Insbesondere bei Rekursion können sie Fehlerbehandlung sehr vereinfachen und in ihnen lassen sich gleich detailliertere Informationen über die Art des Fehlers speichern - die "C-Approach", nur nen Fehlercode zurückzuliefern unter dem sich der Programmierer/der Benutzer dann was vorstellen soll, finde ich da ziemlich braindead. In ner Exception kann ich dann auch gleich schreiben, welche Datei nicht geöffnet werden konnte, in welcher Rekursionstiefe das Problem aufgetreten ist, und diese Informationen an der relevanten Stelle wieder auswerten, ohne sie erstmal dahin transportieren zu müssen.
Sind Assertions nicht auch nur Exceptions, die unter bestimmten Umständen fliegen?Zitat
Ich würde sagen, intern auch für trivialere Dinge verwenden, wenns die einfachste Implementierung ist, nach außen nur kommen lassen, wenn der Aufrufende Schuld ist. Wenns ein UI gibt, und der User Schuld ist, natürlich schon fangen, aber dem User präsentieren und so...Zitat
Anyway, netter Artikel...
Ich sehe schon, ich hatte eher die C-Assertions im Sinn, als die Assertions aus Java, die sich offenbar darin unterscheiden, dass in C eine fehlgeschlagene Assertion zum sofortigen Abbruch des Programms mit einer entsprechenden Fehlermeldung in der Ausgabe führt, während Java eine Exception wirft. Im Endeffekt ist die Definition der Assertion in beiden Fällen aber natürlich identisch, denn es geht dabei um Bugs im Programmcode und nicht um die Behandlung von fehlerhaftem Userinput.
Jedenfalls habe ich auch schon Leute gesehen, die grundsätzlich Assertions (C/C++) den Exceptions vorziehen, nicht zuletzt aus performancetechnischen Gründen, die natürlich unter Umständen auch gerechtfertigt sein können, aber nicht grundsätzlich und meiner Meinung nach auch nicht in der Regel.
Was ich mit "Strategie" im Sinn hatte, war eher in Richtung wie eure Exceptionhierarchie aussieht, falls eine vorhanden. Ob ihr benutzerdefinierte Exceptions verwendet, diese rigoros von der Basis-Exceptionklasse, je nach Härte von der entsprechenden, vom Framework zur Verfügung gestellten Exceptionklasse (C++: runtime_error vs. logic_error), oder überhaupt nicht ableitet. Wie ihr eure Ausnahmefälle strukturiert, usw.
Wie bereits geschrieben, habe ich schon einiges an Meinungen zu Exceptions gelesen und natürlich gibt es bei all den Unterschieden in der Auffassung und im Einsatz auch Konstanten, über die ein mehr oder weniger allgemeiner Konsens herrscht.
So sollten Exceptions nicht für den Control Flow verwendet werden, nur tatsächliche Ausnahmefälle markieren (die Definition, was ein Ausnahmefall ist, schwankt natürlich), in diesem Zusammenhang auch: nicht für jeden möglichen Ausnahmefall eine eigene Exceptionklasse erstellen, sondern generalisieren und die Details in die Fehlermeldungen verlagern, selbstverständlich immer eine Basis-Exceptionklasse haben, damit die Ausnahmebehandlungsblöcke nicht "explodieren", etc.
Irgendwo habe mal Folgendes gelesen, was ich hoffentlich richtig wiedergebe, da ich den entsprechenden Kommentar nicht mehr finde und es doch schon eine Weile her ist:
Exceptions sollten immer dann geworfen werden, wenn eine fundamentale Annahme verletzt wurde.
Beispiel: Eine Funktion erhält als Parameter ein Objekt der Klasse List und soll "true" zurückgeben falls die Liste mehr Elemente enthält als 50, anderenfalls "false". Die Annahme, die hier gemacht wird, ist dass der Parameter ein Objekt der Klasse List ist. Übergebe ich nun aber einen Nullzeiger, ist diese Annahme verletzt und die Funktion befindet sich in einem Zustand, aus dem sie nicht mit den definierten Regeln zum Aufrufer zurückkehren kann. Die Funktion muss eine Exception werfen.
Was die Frage angeht, ob Exceptions strikterweise zur OOP gehören, so denke ich auch, dass es nicht notwendigerweise der Fall sein muss. Exceptions werden in der Regel in objektorientierten Programmiersprachen geworfen, allerdings hindert nichts daran PODs oder Basistypen zu werfen, wie C++ es eindrucksvoll demonstriert: Java-Leute würden sich davor sträuben, was man dort alles werfen kann.
Naja, jedenfalls sind Exceptions eine relativ komplizierte Sache, wenn man tiefer eintaucht und ihren Sinn verstehen und sie sinngemäß einzusetzen wissen will, meinen eigenen Beobachtungen (die mich einschließen) jedenfalls zur Folge. Einige sind ja immernoch der Meinung Exceptions werden heute noch missverstanden und das sogar auf dem Level von Frameworks wie .NET oder Java. Darüber, dass viele Programmierer nichtmal wissen, was Exceptions sind, geschweige denn, wie man sie richtig einsetzt und sie nicht zuletzt aus diesem Grund meiden, herrscht sowieso ein allgemeiner Konsens, denn dass Exceptions ein mächtiges Werkzeug sind, ist nicht abzustreiten.
In C++ sind Exceptions sowieso ein Fall für sich und es werden dem Entwickler viele Steine in den Weg gelegt, so etwa bei dynamischen Bibliotheken plus Exceptions, so dass ich durchaus den ein oder anderen verstehen kann, wenn er sie ablehnt.
Geändert von Kyuu (07.06.2010 um 23:01 Uhr)
Hier mal ein Negativ-Code :-)
Mich persönlich würde ja die exakte Arbeitsweise von Exceptions interessieren. Wie genau funktioniert das interne Abfangen? Muss man sich vorstellen das der Code im Try Block geparst wird oder ähnliches? Sprich das bei einem Indexzugriff eines Arrays bspw. vorher durch die Exception geprüft wird ob der Zugriff ungültig wäre?
Gibt es da vielleicht eine Arbeit zu ? Oder weiß es sogar "zufällig" wer?
--
Hm, klingt nicht so, als hättest du das Prinzip verstanden. Lies dir am besten mal den Wikipedia-Artikel zu Exception Handling durch, die sind meist gute erste Anlaufstellen. Ansonsten findet man über Google sicher auch gute Erklärungen.
Zum Selbererklären bin ich gerade zu faul. ^^"
--A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
Nein, du missverstehst meinen Post.
Was Exceptions sind und wie man sie anwendet weiß ich durchaus.
Ich drücke mich wohl unglücklich aus, mich interessiert an sich die genaue technische Implementation. Der Wiki Artikel ist mir nicht unbekannt, den hab ich früher mal gelesen. Der reißt dieses Thema kurz an, jedoch ist er dabei nicht sehr ausführlich. Mich würden da Details interessieren.
--
Stack Frames enthalten Einträge zu Exception Handlern. Sobald eine Exception geworfen wird, wird der Call Stack solange aufgelöst (Stack Unwinding), bis ein passender Exception Handler gefunden wird. Falls auch im untersten Stack Frame kein passender Handler gefunden wird, wird das Programm abgebrochen. Mehr wüsste ich auch nicht.
Java hat generell eine Bereichs- und Typenüberprüfung.
Also bei jedem Zugriff auf irgendwas wird überprüft, ob dieser Zugriff Gültig ist.
Da ist Java schlauer, als C.
So eine Bereichs- und Typenüberprüfung machen auch noch andere Sprachen, wie z.B. (Object) Pascal, nur mit dem Unterschied, dass man in anderen Sprachen die Überprüfung deaktivieren kann. Bei Java ist sie zwingend erforderlich.
Wenn der JVM (Java Virtual Maschine) irgendwas nicht gefällt, schmeißt die JVM eine Exception.
Nein ist es nicht. C ist sich dieses Mangels durchaus bewusst, hat ihn aber absichtlich aus Performancegruenden in Kauf genommen. C ist nun einmal darauf designed, nur das noetigste zu machen um moeglichst viel Speed rauszuholen. Und bei jedem Indexzugriff eine Bereichsueberpruefung zu machen, ist definitiv eine vVerschwendung von Prozessorzyklen.
C geht in seiner Philosophie davon aus, dass der Programmierer genau weiss, was er tut, er also keinerlei Fehler macht per Definition. Es ist eben nur eine Art komfortablerer Assembler.
Das erinnert mich ein bisschen an http://99-bottles-of-beer.net/language-java-866.html
--A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
dead_orc: Stimmt, wobei nicht alle exceptionfähige Sprachen einen finally-Konstrukt bieten, wie z.B. C++, allerdings ist es dort möglich mittels des RAII-Pattern Vergleichbares zu implementieren.
Exceptions sind eindeutig eine der besseren Erfindungen, und imo auch eine die notwendig war. Der C-Approach ist ja wirklich bescheuert – wenn guter Stil so aussieht, dass man jeden einzelnen Funktionsaufruf in ein if wrapped, kann irgendwas mit der Sprache nicht ganz stimmen. o_O" Exceptions sorgen da gleich für viel mehr Ordnung und erleichtern auch vieles ungemein.
Strikte Regeln, wann man Exceptions einsetzen soll, würde ich mir keine machen – einfach einsetzen, wenn sie den Code lesbarer, klarer oder sonstwie "besser" machen, das sollte man mit etwas Erfahrung dann schon einschätzen können. Natürlich nicht komplett zweckentfremden und z.B., wie manche es schon gemacht haben, als Ersatz für Rückgabewerte nehmen. o_O" Aber wenn etwas in einer Methode schief gehen kann, sollte sie dann imo auch eine entsprechende Exception werfen. Zumindest, wenn das die Methode nicht selber ausbügeln kann.
Und @ Orcey: Naja, Exceptions sind nicht wirklich OOP-spezifisch, auch wenn sie großteils wohl echt in OOP-Sprachen vorkommen. Aber in PHP z.B. gibt's auch welche – Objekte zwar auch, aber man bekommt auch Exceptions ohne je ein anderes Objekt angefasst zu haben. Für ein echtes Beispiel müsste ich allerdings scharf nachdenken – oder natürlich bei Wikipedia cheaten. XD Ah, Prolog hätte mir sogar einfallen können…*kratz*
Und weird, ich dachte PHP hätte schon vor v5 was Exception-mäßiges gehabt…o_O"
--A human is a system for converting dust billions of years ago into dust billions of years from now via a roundabout process which involves checking email a lot.
Ich hatte tatsächlich schon 1x den Fall wo ich vor der Wahl stand: Entweder per Exception einen alternativen Rückgabewert liefern oder umfangreiche Strukturänderungen durchführen. Hab mich für ersteres entschieden. Ich finde die Möglichkeit per Exception nicht nur im Fehlerfall sondern auch allgemein Abzweigungen einzubauen auch ziemlich interessant, auch wenn sie dafür nicht gedacht sind. Die Angst davor, von meinen Arbeitskollegen im Schlaf attackiert zu werden hat mich bisher aber davon abgehalten sowas auch wirklich auszuprobieren.![]()
Ich habe an der Uni mal einen Übungszettel so gelöst, daß jegliche Kommunikation innerhalb des Programms über Exceptions stattfand. Die Punkte gab's, auch wenn der Code schrecklich war.
Uh Exceptions... Leider kann ich nur von Java berichten und was ich da gelernt habe ließ mich genau auf die Fragen stoße die du die gestellt hast: "Welchen Sinn machen sie?" In Java sind ja so gut wie alle Exceptions bereits vorhanden und eigene lohne sich imho nur für das hochpropagieren oder bei den erwähnten komplexen Rekursionen.
Ansonsten finde ich, das es den Code unnötig auf bläht.
Ich weiß nicht wie es in C++ ist, aber in Java gibt es ja sowieso checked und uncheked Exceptions, also solche die gefangen werden müssen und solche die nicht gefangen werden müssen. So wird man in IDE's soweiso sofort darauf aufmerksam gemacht das man hier einen Try-Block benötigt oder aber die Exception propagiert.