C++0x checked exceptions?



  • Das Problem welches sich bei Java gezeigt hat ist dass es ab und an mal vorkommt dass im Interface etwas vergessen wurde.

    Wenn ich nun eine Funktion habe die laut Interface keine (checked) Exception werfen darf, und dann im nachhinein draufkomme dass eine konkrete Implementierung dieses Interface einfach nicht mit den aufgezwungenen Exception-Specs machen kann... doof.

    Oder wenn ich die Implementierung dringend ändern will (weil sie z.B. viel zu langsam ist, oder Fehler enthält, oder was auch immer), dies aber nicht kann ohne in einer Funktion die ehemals als "ich werfe nix" gekennzeichnet war nun doch was zu werfen ... auch doof.

    In dem Fall wirft man in Java dann einfach eine unchecked Exception ... was auch nicht Sinn der Sache ist.

    Real sieht das dann so aus: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4615343

    p.S.: da finden sich dann Kommentare wie

    One can not change entries() to throw a ZipException -
    it is too late.
    One could parse entries in ZipFile constructor, and
    throw a ZipException if the entry is invalid

    Danke, checked Exceptions 😉

    p.p.S.: in "eigenem" Code (auch wenn's ne kleine bis mittelgrosse Firma ist), sehe ich das Problem eher weniger. Einfach die Exception-Spec ändern, und so lange bei allen Projekten "compile drücken, Fehler durchgehen, Exception nachtragen oder fangen, compile drücken, ..." spielen bis es überall durchgezogen ist.
    Im Framework Code, oder wenn's mal ne grössere Firma ist ... ist's halt etwas sehr doof.



  • Das hört man ja ziemlich oft "man kann nicht nachträglich eine Exception hinzufügen, dann compiliert der Code nicht mehr". Dieses Argument zehntausendmal zu bringen, macht es aber nicht richtiger und zeigt IMHO ganz genau auf, wie misverstanden checked Exceptions sind.

    Wenn ich eine neue Exception werfe, dann breche ich Clientcode. Und zwar immer. Egal, ob sie checked ist oder nicht. Wenn sie nicht checked ist, führt das vielleicht nicht zu Compilerfehlern sondern zu Laufzeitfehlern, besser ist das aber keineswegs. Ich hatte vorher Code, der in allen möglichen Situationen robust war und es jetzt nicht mehr ist, möglicherweise sogar von mir unbemerkt. Da sind mir Compilerfehler lieber. Die Abwesenheit von Compilerfehlern bedeuted umgekehrt nicht, dass der Code noch funktioniert.

    p.S.: da finden sich dann Kommentare wie Zitat:
    One can not change entries() to throw a ZipException -
    it is too late.
    One could parse entries in ZipFile constructor, and
    throw a ZipException if the entry is invalid

    Danke, checked Exceptions

    Es ist nicht wegen checked Exceptions zu spät. Es ist zu spät, weil kein Clientcode mit dieser Exception rechnet.

    Probleme mit checked Exceptions sehe ich eher im Aufwand während der Entwicklung. Wenn sich ständig was ändert, verliert irgendwann jeder im Team die Lust, die Exception-Spezifikationen überall anzupassen und wirft nur noch unchecked. Das ist verständlich und man bräuchte IMHO einen Weg, checked Exceptions zunächst einmal ignorieren zu können und vor dem Release dann zu aktivieren.

    - Optimizer



  • Wenn ich eine neue Exception werfe, dann breche ich Clientcode. Und zwar immer.

    Nö, der Clientcode kann ja die Exception in Klasse A einführen und in B fangen, aber dazwischen sitzt ein generisches Framework, das dank Checked Exceptions die Exception nichtmal einfach durchreichen kann. Danke aber auch.



  • Bashar hat es ja gesagt - aber ein weiteres Problem hier ist eben dass viele Leute denken dass der Exception Typ relevant ist. Das ist er aber nicht. Zumindest meistens. Ganz selten ist er mal interessant aber meistens fange ich einen Fehler. Was das für ein Fehler ist, ist mir meistens egal:

    Fakt: ich konnte die Datei nicht öffnen.
    Grund: entweder Datei nicht da, nicht genügend rechte, datei ist gelockt etc.

    Wichtig für mich ist: die Datei ist nicht offen und darauf muss ich reagieren.

    Die grundlegende Idee ist ja nicht schlecht, aber in der praxis ist es einfach unpraktikabel.



  • Shade Of Mine schrieb:

    Beruf: System Administrator

    Musst du als System Admin soviel mit C++ programmieren oder machst du das privat?



  • Benutzerprofil schrieb:

    Shade Of Mine schrieb:

    Beruf: System Administrator

    Musst du als System Admin soviel mit C++ programmieren oder machst du das privat?

    C++-Sysadmins – kennste nicht? Das sind die Leute, die immer schnell ein C++-Skript mit Boost.Regex und Boost.Filesystem zusammenhacken, statt „grep“, „tr“ und „sed“ zu verwenden. :-p

    (Shade weiß hoffentlich, dass das nicht ernst (oder gar bös) gemeint war.)



  • Benutzerprofil schrieb:

    Shade Of Mine schrieb:

    Beruf: System Administrator

    Musst du als System Admin soviel mit C++ programmieren oder machst du das privat?

    ich arbeite mehr mit c++ als mir lieb ist 😉



  • Bashar schrieb:

    Wenn ich eine neue Exception werfe, dann breche ich Clientcode. Und zwar immer.

    Nö, der Clientcode kann ja die Exception in Klasse A einführen und in B fangen, aber dazwischen sitzt ein generisches Framework, das dank Checked Exceptions die Exception nichtmal einfach durchreichen kann. Danke aber auch.

    Also hab ich nicht den direkt abhängigen Clientcode gebrochen, sondern den indirekt abhängigen. Wir verstecken den Fehler immer besser, nähern uns bald der Perfektion. 😃

    Shade Of Mine schrieb:

    Bashar hat es ja gesagt - aber ein weiteres Problem hier ist eben dass viele Leute denken dass der Exception Typ relevant ist. Das ist er aber nicht. Zumindest meistens. Ganz selten ist er mal interessant aber meistens fange ich einen Fehler. Was das für ein Fehler ist, ist mir meistens egal:

    Fakt: ich konnte die Datei nicht öffnen.
    Grund: entweder Datei nicht da, nicht genügend rechte, datei ist gelockt etc.

    Wichtig für mich ist: die Datei ist nicht offen und darauf muss ich reagieren.

    Die grundlegende Idee ist ja nicht schlecht, aber in der praxis ist es einfach unpraktikabel.

    Wenn dich der Exception-Typ nicht interessiert, dann fang doch in deinem Clientcode die allgemeine Exception. Dann stört es dich auch nicht, wenn der andere seine Spezifikation etwas anpasst. Wenn du z.B. eine allgemeine IOException fängst weil es dir reicht zu wissen dass eine Datei nicht geladen wurde, dann ist es dir auch egal, wenn ich nachträglich noch eine AccesDeniedException hinzufüge.



  • Optimizer schrieb:

    Wenn dich der Exception-Typ nicht interessiert, dann fang doch in deinem Clientcode die allgemeine Exception. Dann stört es dich auch nicht, wenn der andere seine Spezifikation etwas anpasst. Wenn du z.B. eine allgemeine IOException fängst weil es dir reicht zu wissen dass eine Datei nicht geladen wurde, dann ist es dir auch egal, wenn ich nachträglich noch eine AccesDeniedException hinzufüge.

    Nicht desto trotz wiederspricht immer noch eine checked exceptions dem Policy-Design und einigen anderen Template-Techniken.

    Wenn ich eine Templateklasse für Policies designe, KANN ich vorher garnicht wissen ob, und wenn welche Exceptions in Frage kommen können. Soll ich nun den Schreiber einer Policyklasse aufzwingen das er die Exception xyz verwenden muss?

    Falls jemand das Prinzip von Policy-Klassen noch nicht verstanden hat soll er sich mal "Modern C++ Design" und die Loki-Bibliothek anschauen, letztere ist sehr stark darauf ausgelegt.

    cu André



  • asc schrieb:

    ...sich mal "Modern C++ Design" und die Loki-Bibliothek anschauen, ...

    Ach ja *schwärm* das steht auch noch auf meiner Wunschliste ...

    Gruß,

    Simon2.



  • Der Denkfehler ist, du müsstest jetzt wissen ob eine FileNotFoundException oder was auch immer kommen kann, aber das kann für jede Policy verschieden sein. Musst du aber nicht wissen. Wenn du Exception-Handling für deine Policies brauchst (wovon ich in den meisten Fällen nicht ausgehe), definierst du eine eigene Exception "kann dies und das nicht machen" und einigst dich darauf, dass alle Policies nur diese Exception werfen dürfen.

    Das ist Standard-Vorgehen das du auch ohne checked Exceptions benötigst, wie könntest du sonst deinen Code absichern? Wenn du Policy-Objekte benutzt, hast du gewisse Annahmen darüber, wie sie sich verhalten und Exceptions gehören zu diesem Verhalten dazu. Wenn du keine Annahmen darüber machen kannst, kannst du deinen Code auch nicht absichern. Das Checking verursacht die Probleme also nicht, sondern zeigt die bereits vorhandenen nur auf.

    Ich habe wie gesagt eher das Problem, dass sie zu unflexibel sind so lange man an dem Programm noch entwickelt und ständig was ändern muss. Ich sehe aber keinen Konflikt mit üblichen Paradigmen.



  • Optimizer schrieb:

    Wenn du Exception-Handling für deine Policies brauchst (wovon ich in den meisten Fällen nicht ausgehe), definierst du eine eigene Exception "kann dies und das nicht machen" und einigst dich darauf, dass alle Policies nur diese Exception werfen dürfen.

    Das ist u.U. eine zu starke Einschränkung.

    Das ist Standard-Vorgehen das du auch ohne checked Exceptions benötigst, wie könntest du sonst deinen Code absichern?

    Nein. Der Client weiß ja üblicherweise (zumindest irgendwo), welche Policy er verwendet, d.h. er weiß auch (irgendwo), welche Ausnahmen auftreten können und kann dort (= irgendwo) entsprechend reagieren. Das geht aber eben nur, wenn die Policy-parametrisierte Klasse diese Ausnahme überhaupt zulässt, und das ist eben durch Checked Exceptions stark beschnitten.

    Wenn du Policy-Objekte benutzt, hast du gewisse Annahmen darüber, wie sie sich verhalten

    Das ist eben nicht unbedingt der Fall. Zumindest nicht aus Sicht der allgemeinen, parametrisierten Klasse. Der Client macht natürlich Annahmen, aber der hat leider keinen Einfluss auf die von der parametrisierten Klasse erlaubten Ausnahmen.

    => Ich habe den Eindruck, dass Du hier die verschiedenen Akteure im Programmfluss durcheinanderbringst.



  • ihr stellt euch an. wenns Checked-Exceptions gäbe, warum sollte man dann den Exceptiontyp nicht per Template festlegen können? Fertig, Policy-Prinzip geht wieder.



  • Optimizer schrieb:

    Bashar schrieb:

    Wenn ich eine neue Exception werfe, dann breche ich Clientcode. Und zwar immer.

    Nö, der Clientcode kann ja die Exception in Klasse A einführen und in B fangen, aber dazwischen sitzt ein generisches Framework, das dank Checked Exceptions die Exception nichtmal einfach durchreichen kann. Danke aber auch.

    Also hab ich nicht den direkt abhängigen Clientcode gebrochen, sondern den indirekt abhängigen.

    Kannst du das ausführen? Was meinst du mit indirekt abhängigem Clientcode, und warum sollte dieser gebrochen sein?



  • Optimizer schrieb:

    Wenn du Exception-Handling für deine Policies brauchst (wovon ich in den meisten Fällen nicht ausgehe),

    Eine der häufigsten Policies die ich kenne hat mit dem Anlegen und Freigeben zu tun. Je nach Policy, die auch ein Anwender der Klasse selbst definieren kann, muss es dabei nicht zwangsläufig sein das die generierung überhaupt Fehlschlagen kann (Nehmen wir einfach mal an das hier garkein neues Objekt generiert, sondern im Hintergrund einfach nur auf ein statisches Array zugegriffen wird).

    Zudem kann der Schreiber der Policy dann auch auf Ideen kommen die du garnicht in deinen Entwurf berücksichtigt hast. Und nun? Tolle Einschränkung, echt Klasse.

    Optimizer schrieb:

    definierst du eine eigene Exception "kann dies und das nicht machen" und einigst dich darauf, dass alle Policies nur diese Exception werfen dürfen.

    Du solltest dich vielleicht mal überhaupt mit dem Thema Policy-Klassen genauer beschäftigen. Es gibt bei Policy-Klassen auch keinerlei...

    Optimizer schrieb:

    Wenn du Policy-Objekte benutzt, hast du gewisse Annahmen darüber, wie sie sich verhalten und Exceptions gehören zu diesem Verhalten dazu.

    Annahmen zu den Klassenaufbau. Das Einzige was du vielleicht fest machst ist das eine Methode mit dem und dem Namen vorhanden sein muss. Wobei Policies auch weit über deine Annahmen hinaus gehen können.

    Optimizer schrieb:

    Wenn du keine Annahmen darüber machen kannst, kannst du deinen Code auch nicht absichern. Das Checking verursacht die Probleme also nicht, sondern zeigt die bereits vorhandenen nur auf.

    Du als Anwender der Policies kannst sehr wohl Annahmen über die Policies treffen, nicht aber der Entwickler des Klassentemplates das aus den Policies aufgebaut wird. Daher kann eben dieser KEINERLEI "checked exceptions" verwenden, ohne den Anwender die Flexibilität zu nehmen.

    Optimizer schrieb:

    Ich sehe aber keinen Konflikt mit üblichen Paradigmen.

    Ich schon Policy-Klassen und "checked exceptions" widersprechen sich. Wenn du anderer Meinung bist, solltest du dich auch erstmal ernsthaft mit dem Thema Policy-Klassen auseinander setzen. Nach deinen Geschreibe gehe ich davon aus das du maximal die Grundlagen darüber mal gehört, aber es noch nie ernsthaft angewendet, oder nur mit den vordefinierten Policies hantiert hast.

    Und Policy-Klassen sind nur eine der Templatetechniken die als Beispiel genannt wurden sind. Grundsätzlich sehe ich auch bei einfach verschachtelten Templates (Die über typedefs aus anderen Templates aufgelöst werden), Große Probleme bezüglich "checked exceptions".

    cu André



  • mannn schrieb:

    ihr stellt euch an. wenns Checked-Exceptions gäbe, warum sollte man dann den Exceptiontyp nicht per Template festlegen können? Fertig, Policy-Prinzip geht wieder.

    Dann müsste man das aber noch ganz stark ausweiten. Ich sage mal bedingte checked-exceptions (Da eine Policy zwischen 0..n Exceptionfälle haben kann) etc.

    Weiß du, man kann auch mit einem Ferrari einen Brief zum 10m entfernten Briefkasten bringen, oder mit einem Bobbycar von München nach Hamburg fahren. In wie weit das Sinn macht, ist die andere Frage.

    Manche bezeichnen C++ schon jetzt als komplexe Sprache, wieviele Sprachmittel braucht es eigentlich noch?

    cu André
    P.S: Tatsächlich würde ich mir von C++ Standard noch 2 Sachen wünschen:
    a) Eine portable Definition um über Schnittstellen auch mit C++ Elementen Daten auszutauschen (Auch über Compilergrenzen hinweg).
    b) Eine UI-Bibliothek die auch tatsächlich die Standardlib einsetzt (Sprich auch mit std::string, std::wstring etc. klar kommt).



  • Optimizer schrieb:

    Bashar schrieb:

    Wenn ich eine neue Exception werfe, dann breche ich Clientcode. Und zwar immer.

    Nö, der Clientcode kann ja die Exception in Klasse A einführen und in B fangen, aber dazwischen sitzt ein generisches Framework, das dank Checked Exceptions die Exception nichtmal einfach durchreichen kann. Danke aber auch.

    Also hab ich nicht den direkt abhängigen Clientcode gebrochen, sondern den indirekt abhängigen. Wir verstecken den Fehler immer besser, nähern uns bald der Perfektion. 😃

    nein, weil der typ egal ist. client code der bricht weil ein anderer typ exception geflogen ist, ist kaputt. es kann zB immer ein out of memory fliegen und das fange ich nie explizit ab - aber dafür habe ich ja generisches exception handling dass eben exception bearbeitet ohne sie kennen zu müssen.

    Wenn dich der Exception-Typ nicht interessiert, dann fang doch in deinem Clientcode die allgemeine Exception. Dann stört es dich auch nicht, wenn der andere seine Spezifikation etwas anpasst. Wenn du z.B. eine allgemeine IOException fängst weil es dir reicht zu wissen dass eine Datei nicht geladen wurde, dann ist es dir auch egal, wenn ich nachträglich noch eine AccesDeniedException hinzufüge.

    Das Problem ist nur, dass es nicht nur IOException gibt sondern auch SecurityException und eine OutOfMemoryException kann sowieso ach noch immer fliegen. Eine Datei Operation kann eben auch anderes als IOExceptionmäßiges werfen.

    Beispiel eine Datenbank. Am Anfang kann nur eine DatabaseAccessException fliegen. Später plötzlich kommen Security Policies dazu und ich habe das Problem dass ich SecurityPolicy Exception plötzlich zwangsläufig in die DatabaseAccessException hierachie packen muss anstatt die bestehende Hierachie zu verwenden.

    Der Typ von Objekten ist in der oop immer egal. vorallem vielen funktionen sind exception total egal: man nennt sie exception neutrale funktionen. sie werfen alle exception einfach durch.

    mit templates ist es sowieso unmöglich checked exceptions sinnvoll zu forcieren. es ist eben nicht sinnvoll machbar exception restriktionen an policies zu setzen da man dadurch die wiederverwendbarkeit senkt. auch in java tut man sich mittlerweile schwer und ist zu dem konsens gekommen dass checked exception eine nette idee waren und mehr nicht.

    siehe auch: http://www.mindview.net/Etc/Discussions/CheckedExceptions

    aber wir haben diese diskussion schon vor vielen jahren geführt 😉



  • Bashar schrieb:

    Kannst du das ausführen? Was meinst du mit indirekt abhängigem Clientcode, und warum sollte dieser gebrochen sein?

    Vielleicht verstehe ich dich falsch. Wenn du in deinem Beispiel meintest man hätte die Möglichkeit, B an die neue Spezifikation anzupassen, nur das Framework dazwischen nicht, dann ist das möglicherweise schon ein guter Punkt.

    Ich möchte aber auch anmerken, dass so ein Framework normalerweise aus einem guten Grund existiert und das Framework unter Umständen dafür verantwortlich sein müsste, die Exception zu fangen und darauf zu reagieren. Vielleicht hast du in deinem B die Möglichkeit, die Exception zu fangen, aber das ist nicht notwendigerweise sinnvoll. Nimm zum Beispiel:

    Anwendung <-> O/R-Mapper <-> Datenbank

    Und das Datenbanksystem könnte jetzt eine neue Exception werfen. Der O/R-Mapper hat die Aufgabe, die Tabellen umzufüllen in andere Strukturen und dabei transparent Details der Datenbank, wie z.B. das aufrechterhalten der Verbindung zu verbergen und macht in diesem Sinne auch das Exception-Handling "Socket kann nicht erstellen werden" oder "insert MS SQL Server specific error here" und zeigt der Anwendung etwas allgemeineres an.

    Jetzt würdest du bestimmt gar nicht wollen, dass du in deiner Anwendung irgendwelche MS SQL-Fehler fangen musst, die neu hinzukommen. Es ist also ohnehin nötig, das Framework anzupassen und "einfach durchreichen" ist keine Lösung.



  • Optimizer schrieb:

    Jetzt würdest du bestimmt gar nicht wollen, dass du in deiner Anwendung irgendwelche MS SQL-Fehler fangen musst, die neu hinzukommen. Es ist also ohnehin nötig, das Framework anzupassen und "einfach durchreichen" ist keine Lösung.

    ich würde das nicht machen, wenn das framework nicht fangen soll.
    dem framework sind die fehler doch egal. wenn die db keine daten liefert die das framework verarbeiten kann, reicht es den fehler durch. punkt.

    natürlich kann man es auch anders machen, aber es gibt keinen zwingenden grund...



  • Ja, ist jetzt schon auch egal. Ich möchte nicht für checked Exceptions argumentieren und habe seit Jahren mit keiner Sprache mehr gearbeitet, die sowas anbietet. Ich vermisse es auch nicht. Ich habe einfach den Eindruck, dass viel Abneigung aus Misverständnissen entsteht und gerade so einfache Logik wie "ich kann nichts mehr nachträglich ändern" ist mir zu kurz gedacht. Das checked Exceptions in C++ dann nicht genauso aussehen würden wie in Java, scheint auch nicht immer klar zu sein.

    Auf jeden Fall würden checked Exceptions für mich ohnehin ein non-Problem lösen, ich bin schon froh, wenn im Team überhaupt Exceptions benutzt werden oder irgendeine Art von Fehlersignalisierung anstatt eines silent return. 😉 Deswegen ist diese ganze Diskussion für mich eher akademisch interessant.


Anmelden zum Antworten