pl: Wozu Exception Objects

0 85

Wozu Exception Objects

pl
  • programmiertechnik
  1. 2
    dedlfix
    1. 0
      pl
      1. 1
        dedlfix
        1. 0
          pl
          1. 0
            dedlfix
            1. 0
              pl
              • sonstiges
              1. 0
                dedlfix
                1. 0
                  pl
                  1. 0
                    perl
                    • perl
                    1. 0
                      pl
                      1. 0
                        perl
                        1. 0
                          pl
                          1. 0
                            perl
                  2. 0

                    NonSenseException

                    Camping_RIDER
                    • menschelei
      2. 0
        Robert B.
        1. 0
          Matthias Apsel
          1. 0
            Robert B.
            1. 0
              Rolf B
              1. 0
                Robert B.
        2. 0
          pl
          1. 0
            perl
          2. 0
            Rolf B
            1. 0
              pl
              1. 0
                Robert B.
                1. 0
                  pl
                  1. 0
                    Robert B.
              2. 1
                Rolf B
                1. 0
                  pl
                  1. 3
                    Tabellenkalk
          3. 1
            Robert B.
            1. 0
              pl
              1. 0
                Robert B.
                1. 0
                  pl
                  1. 0
                    Robert B.
                2. 1
                  dedlfix
                  1. 0
                    pl
                    1. 0
                      Robert B.
                      1. 0
                        pl
                        1. 0
                          Robert B.
                    2. 1
                      dedlfix
                      1. 0
                        pl
                        1. 0
                          Robert B.
                          • menschelei
                          • programmiertechnik
                        2. 2
                          dedlfix
            2. 1
              1unitedpower
              1. 0
                Robert B.
          4. 2

            Versuch einer Erläuterung zur Sinnhaftigkeit von Exception-Objekten

            Camping_RIDER
            1. 0
              pl
              1. 0
                Robert B.
              2. 0
                Camping_RIDER
            2. 0
              pl
              1. 0
                Robert B.
                • c++
                • programmiertechnik
                1. 0
                  pl
              2. 0
                Camping_RIDER
      3. 0
        Robert B.
        1. 0
          pl
          1. 0
            Robert B.
    2. 0
      Linuchs
      1. 0
        Matthias Apsel
        1. 0
          Linuchsx
          1. 0
            Matthias Apsel
            1. 1
              Christian Kruse
  2. 3
    Matti Mäkitalo
    1. 0
      pl
      1. 4
        Matti Mäkitalo
  3. 0
    Rolf B
    1. 0
      pl
      1. 0
        Rolf B
        1. 0
          pl
  4. 0
    pl
    1. 0
      Robert B.
      1. 0
        pl
        1. 0
          Robert B.
          • menschelei
          • programmiertechnik
          1. 0
            pl
            1. 0
              Robert B.
              • menschelei
    2. 0
      Rolf B
      1. -1
        pl
        1. 1
          Rolf B
          1. 0
            pl
            1. 1
              Mitleser
            2. 2
              Rolf B
              1. 0
                Robert B.
                • zu diesem forum
              2. 0
                JürgenB
                1. 0
                  Camping_RIDER
        2. 0
          Robert B.
          • menschelei

s. Thema. Für was sollen Exception Objekte gut sein?

Bitte mal um Hinweise.

  1. Tach!

    Für was sollen Exception Objekte gut sein?

    Das ist wie bei jeder Art von Objekten: Zusammenfassung von Datenfeldern und Methoden zu einer Einheit. Der Catch-Mechanismus kann darüber hinaus auch anhand der Klassenzugehörigkeit Exceptions fangen oder unbeachtet durchlassen.

    dedlfix.

    1. Hast du mal ein praktisches Beispiel was die Sinnfälligkeit dafür zeigt Exceptions in Klassen zu organisieren und Instanzen gefallener Exceptions zu erstellen?

      1. Tach!

        Hast du mal ein praktisches Beispiel was die Sinnfälligkeit dafür zeigt Exceptions in Klassen zu organisieren und Instanzen gefallener Exceptions zu erstellen?

        Ja klar, gibts überall wo Exceptions derart existieren.

        Wenn man eine Funktion aufruft, kann es viele Ursachen haben, nicht erfolgreich zu sein. Bestimmte Ursachen erwartet man und kann sie vor Ort beheben, andere nicht und überlässt sie dem Aufrufer.

        Ein Beispiel sei das Lesen einer Datei. Ursachen für das Misslingen können sein, dass die Datei nicht existiert oder dass Berechtigungen nicht ausreichen. Man könnte nun die FileNotFoundException abfangen, die Datei anlegen und eine leere Datei zurückgeben. Bei unzureichenden Berechtigungen gibt es keine sinnvolle Sofortmaßnahme. Die AccessDeniedException fängt man also nicht ab und überlässt sie dem Aufrufer.

        Beim Instantiieren übergibt man dem Konstruktor meist nur einen Text und vielleicht noch ein paar andere interessante Parameter. Aber die allgemeinen Dinge, wie Ort des Geschehens und Stacktrace kann der Konstruktor der Exceptionklasse selbst ermitteln und in seine entsprechenden Datenfelder ablegen.

        dedlfix.

        1. Ein Beispiel sei das Lesen einer Datei. Ursachen für das Misslingen können sein, dass die Datei nicht existiert oder dass Berechtigungen nicht ausreichen. Man könnte nun die FileNotFoundException abfangen, die Datei anlegen und eine leere Datei zurückgeben. Bei unzureichenden Berechtigungen gibt es keine sinnvolle Sofortmaßnahme. Die AccessDeniedException fängt man also nicht ab und überlässt sie dem Aufrufer.

          Schön. Aber sowas kann man ja auch ohne Klassen oder gar Exceptionobjects regeln. Was soll da einen Vorteil von OOP begründen?

          1. Tach!

            Schön. Aber sowas kann man ja auch ohne Klassen oder gar Exceptionobjects regeln. Was soll da einen Vorteil von OOP begründen?

            Man kann auch Daten einfach kommasepariert in einen großen String packen. Wozu also überhaupt OOP oder gar Strukturierung? Vielleicht weil sich ein Objekt mit separaten Eigenschaften für die diverse Daten als vorteilhaft in der Anwendung herausgestellt hat?

            dedlfix.

            1. Meine Frage ist, welchen Vorteil OOP in Sachen Exception Handling bietet. OOP zum Selbstzweck ist kein Vorteil von OOP.

              Um in deinem Beispiel zu bleiben: Naürlich muss man sich arüber im Klaren sein, wie man mit einem etwaigen Fehler umgeht. Zum Erstellen einer Datei jedenfalls braucht man keinen Umweg über OOP falls die Datei nicht existiert.

              Und zur Access Control auch nicht. Für all diese Dinge gibt es Dateitestoperatoren u.a. Schnittstellen zum OS.

              Aber vielleicht hast Du noch ein anderes Beispiel?

              1. Tach!

                Um in deinem Beispiel zu bleiben: Naürlich muss man sich arüber im Klaren sein, wie man mit einem etwaigen Fehler umgeht. Zum Erstellen einer Datei jedenfalls braucht man keinen Umweg über OOP falls die Datei nicht existiert.

                Es gibt nicht nur Perl. Andere Systeme, wie Java oder C#, haben nur Klassen und Objekte, um Dinge zu erledigen, da kann nicht nicht ohne OOP eine Datei erstellen, und auch keine Exceptions ohne ein Exception-Objekt werfen. Und die machen das da auch nicht nur zum Selbstzweck, sondern weil das eben deren Philosophie ist, die Dinge zu erledigen.

                Und zur Access Control auch nicht. Für all diese Dinge gibt es Dateitestoperatoren u.a. Schnittstellen zum OS.

                Es gibt nicht nur Perl. Bei C# sind das Methoden der File-Klasse und anderer. Die werfen dann eben Exceptions der betreffenden Klasse für die möglichen unterschiedlichen Fehler.

                Aber die Diskussion bringt nicht weiter ein, wenn du nur deinen Standpunkt bestätigt sehen möchtest und alles andere mit "braucht man nicht" abbügelst.

                dedlfix.

                1. Unter der Haube arbeitet Perl objektorientiert. War schon immer so. OOP heißt ja nur, daß man selbst in dieser Hinsicht tätig wird. Also eine explizite Nutzung. D.h., daß man dafür einen eigenen Grund hat. Wenn man den nicht hat, macht OOP keinen Sinn!

                  1. Unter der Haube arbeitet Perl objektorientiert. War schon immer so.

                    nein: Zitat Perl 5/Changes unter „New things“: „Objects“

                    Perl war schon immer prozedural; OOP kam erst später.

                    1. Perlobjekte gab es schon in Version 4. Was es nicht gab, waren Klassen mit deren Namen man Perlobjekte segnen konnte (bless)!

                      1. Perlobjekte gab es schon in Version 4.

                        Deswegen werden sie auch als große Neuerung von Perl 5 erwähnt… Aber du hast ja sicher einen Beweis für deine Aussage.

                        1. Perlobjekte gab es schon in Version 4.

                          Deswegen werden sie auch als große Neuerung von Perl 5 erwähnt… Aber du hast ja sicher einen Beweis für deine Aussage.

                          Eric Foster Johnson: "Perl Module" Verlag mitp, ISBN 3-8266-0570-5

                          1. Perlobjekte gab es schon in Version 4.

                            Deswegen werden sie auch als große Neuerung von Perl 5 erwähnt… Aber du hast ja sicher einen Beweis für deine Aussage.

                            Eric Foster Johnson: "Perl Module" Verlag mitp, ISBN 3-8266-0570-5

                            Das ist ein Buch von 1999 über Perl 5. Ohne es gelesen zu haben oder ein konkretes Zitat, gehe ich weiterhin davon aus, dass dort nix über Objekte in Perl 4 (und früher) steht. Stattdessen liefere ich mal noch ein Zitat aus der Wishlist von Perl 4.036: „add structured types and objects“

                  2. Aloha ;)

                    Unter der Haube arbeitet Perl objektorientiert. War schon immer so. OOP heißt ja nur, daß man selbst in dieser Hinsicht tätig wird. Also eine explizite Nutzung. D.h., daß man dafür einen eigenen Grund hat. Wenn man den nicht hat, macht OOP keinen Sinn!

                    Also ich an deiner Stelle hätte ja jetzt zu dedlfix gesagt, dass es mir gar nicht um perl geht, denn deine Frage hatte nichts mit perl zu tun, er hat dich aber eben unter den Verdacht gestellt, mal wieder nur perl (in deiner ganz eigenen Interpretation des Themas) im Blick zu haben.

                    Und was tust du? Über perl weiterreden.

                    Respekt, du könntest ein Handbuch darüber schreiben, wie man sich selbst argumentativ ins Aus stellt.

                    Grüße,

                    RIDER

                    --
                    Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                    # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
      2. Moin pl,

        mal der Versuch eines Beispiels aus den Naturwissenschaften: Im Allgemeinen ist die Division durch 0 nicht definiert, durch Grenzwertbildung kann man allerdings unendlich als Ergebnis setzen. Die Divison durch 0 ist ein arithmetischer Fehler, objektorientiert gesprochen also eine abgeleitete Klasse, in C++ könnte man das so modellieren:

        class DivisionDurch0 : public ArithmetischerFehler {
            // …
        };
        

        Die Vision wäre dann z.B. wie folgt modelliert:

        float operator/(const float z, const float n) {
            if (n == 0.) {
                throw DivisionDurch0;
            }
        
            return z / n;
        }
        

        Ein Taschenrechner o.ä. wird im Allgemeinen Rechenfehler abfangen, während eine Anwendung aus der Physik mit unendlich umgehen kann, d.h.:

        // Taschenrechner:
        try {
            float erg = zaehler / nenner;
        }
        catch (ArithmetischerFehler &af) {
            // …
        }
        
        
        // Unendlich
        float erg;
        
        try {
            erg = zaehler / nenner;
        }
        catch (DivisionDurch0 &dd0) {
            erg = INFINITY;
        }
        

        Viele Grüße
        Robert

        1. Hallo Robert B.,

          mal der Versuch eines Beispiels aus den Naturwissenschaften: Im Allgemeinen ist die Division durch 0 nicht definiert, durch Grenzwertbildung kann man allerdings unendlich als Ergebnis setzen.

          Nur, wenn der Dividend nicht auch Null ist.

          Bis demnächst
          Matthias

          --
          Pantoffeltierchen haben keine Hobbys.
          1. Hallo Matthias,

            mal der Versuch eines Beispiels aus den Naturwissenschaften: Im Allgemeinen ist die Division durch 0 nicht definiert, durch Grenzwertbildung kann man allerdings unendlich als Ergebnis setzen.

            Nur, wenn der Dividend nicht auch Null ist.

            Kommt darauf an, was zuerst gegen Null geht.

            Viele Grüße
            Robert

            1. Hallo Robert,

              vorsicht, das kann einen ins Hospital bringen!

              Rolf

              --
              sumpsi - posui - clusi
              1. Moin Rolf,

                ins Spital im fränkischen Sinne würde mir reichen 😉

                Prost,
                Robert

        2. throw DivisionDurch0;

          Nun, wenn throw() eine Klasse als Argument nimmt, ist das so. Vermutlich wird unter der Haube eine Klassenvariable gesetzt. Auf jeden Fall steckt eine statische Variable dahinter, welche den Fehlertext beeinhaltet.

          Die Frage ist, welchen Vorteil es bringt, anstatt eines Fehlertextes an throw() eine Klassenmethode bzw. den Namen einer Klasse zu übergeben? Womit wahrscheinlich sogar eine Instanz erzeugt wird, aber wozu?

          MfG

          1. Die Frage ist, welchen Vorteil es bringt, anstatt eines Fehlertextes an throw() eine Klassenmethode bzw. den Namen einer Klasse zu übergeben?

            https://forum.selfhtml.org/self/2018/nov/13/wozu-exception-objects/1736372#m1736372

          2. Hallo pl,

            da hamma ja was losgetreten im anderen Thread 😉

            Nein, da steckt keine statische Variable hinter. Fehlermeldung und sonstige Informationen liegen als Instanzvariablen am Exception Objekt. C++ ist da nur etwas eigen - man kann throw mit und ohne new verwenden und bekommt im Catch dann entweder einen Pointer (den man selbst deallocieren muss) oder eine Referenz (die C++ für einen deallociert) auf das erzeugte Objekt.

            Rolf

            --
            sumpsi - posui - clusi
            1. @Rolf B

              da hamma ja was losgetreten im anderen Thread 😉

              Das war nur der Anlass. Aber die Frage beschäftigt mich schon länger.

              Nein, da steckt keine statische Variable hinter. Fehlermeldung und sonstige Informationen liegen als Instanzvariablen am Exception Objekt.

              Und schon wären wir auch damit wieder bei der Frage: Wozu eine Instanz?

              Perl's Error.pm ist übrigens deprecatet. Und mit v6 ist Perl nicht mehr das was es mal war.

              Mit dem bisherigen Exceptionmodel jedenfalls lässt sich jedes Problem lösen ohne Exception Objekte zu erstellen. Vielleicht sollte man die Frage mal anders angehen: Machen mehrere Instanzen von Exceptionklassen einen Sinn? Denn das hieße ja, daß man spätestens beim Erstellen der 2. Exceptioninstanz die 1. Exception ignoriert hat!

              MfG

              1. Moin,

                Machen mehrere Instanzen von Exceptionklassen einen Sinn? Denn das hieße ja, daß man spätestens beim Erstellen der 2. Exceptioninstanz die 1. Exception ignoriert hat!

                das hat seinen Sinn, sobald du mehrere Stellen hast, an denen Exceptions geworfen werden können, vielleicht sogar parallel.

                Viele Grüße
                Robert

                1. Moin,

                  Machen mehrere Instanzen von Exceptionklassen einen Sinn? Denn das hieße ja, daß man spätestens beim Erstellen der 2. Exceptioninstanz die 1. Exception ignoriert hat!

                  das hat seinen Sinn, sobald du mehrere Stellen hast, an denen Exceptions geworfen werden können, vielleicht sogar parallel.

                  Genau diese Stellen setzt man in einen try{}Block. Und wenn man 2 dieser möglichen Stellen in einen try{}Block setzt, sollte man daran denken, daß eine 2. EX gar nicht fallen kann wenn die 1. EX gefallen ist. catch() kriegt also entweder die eine oder die andere Ursache übergeben.

                  In Form

                  1. eines Literals
                  2. oder einer Referenz
                  3. oder einer Klasse
                  

                  Und da wären wir wieder bei meiner Frage: Wozu soll 3. Gut sein!?

                  Abgesehen davon daß man mehrere EX Verdächtigte besser nicht in einen try{}Block setzt.

                  .

                  1. Moin,

                    Machen mehrere Instanzen von Exceptionklassen einen Sinn? Denn das hieße ja, daß man spätestens beim Erstellen der 2. Exceptioninstanz die 1. Exception ignoriert hat!

                    das hat seinen Sinn, sobald du mehrere Stellen hast, an denen Exceptions geworfen werden können, vielleicht sogar parallel.

                    Genau diese Stellen setzt man in einen try{}Block. Und wenn man 2 dieser möglichen Stellen in einen try{}Block setzt, sollte man daran denken, daß eine 2. EX gar nicht fallen kann wenn die 1. EX gefallen ist. catch() kriegt also entweder die eine oder die andere Ursache übergeben.

                    Wenn du wissen möchtest, welchen Sinn mehrere Exception-Objekte in einem try-catch-Block haben, dann frage bitte auch dementsprechend. Meine Antwort hat sich auf die oben zitierte allgemeine Frage nach dem Sinn mehrerer Exception-Objekte in einem Programm (Thread?) bezogen.

                    Natürlich kann von den verschiedenen möglichen Exceptions immer nur eine fallen, aber es kann es eine der verschiedenen sein, in dem Taschenrechnerbeispiel neben der Division durch Null z.B. auch eine Unter- oder Überschreitung des Wertebereichs oder in dem Beispiel mit der Parser-Exception könnte es auch eine Exception der darunterliegenden IO-API sein, lies: Das Parsen kann fehlschlagen, wenn nicht aus der Datei gelesen oder der Dateiinhalt fehlerhaft ist.

                    In Form

                    1. eines Literals
                    2. oder einer Referenz
                    3. oder einer Klasse
                    

                    Und da wären wir wieder bei meiner Frage: Wozu soll 3. Gut sein!?

                    Was genau meinst du mit Klasse? In meinen Beispielen wird keine Klasse geworfen, sondern Objekte von Klassen.

                    Abgesehen davon daß man mehrere EX Verdächtigte besser nicht in einen try{}Block setzt.

                    Also in dem Parserbeispiel lieber

                    FileOfSpecificType f = NULL;
                    
                    try {
                        f = new FileOfSpecificType(filePathAndName);
                    }
                    catch (IOError &ioe) {
                        std::cerr << "Could not open " << filePathAndName << " for reading: "
                            << ioe.what() << '\n';
                    }
                    catch (SecurityException &se) {
                        std::cerr << "Permission denied: " << filePathAndName << '\n';
                    }
                    catch (MemoryError &me) {
                        std::cerr << "Could not allocate enough memory for parsing " << filePathAndName
                            << ": " << me.what() << '\n';
                    }
                    
                    if (!f) return;
                    
                    try {
                        objekts = f->parse();
                    }
                    catch (IOError &ioe) {
                        std::cerr << "Could not parse " << filePathAndName << ": "
                            << ioe.what() << '\n';
                    }
                    catch (MemoryError &me) {
                        std::cerr << "Could not allocate enough memory for parsing " << filePathAndName
                            << ": " << me.what() << '\n';
                    }
                    catch (ParserException &pe) {
                        std::cerr << "Unexpected token " << pe.token() << " in " << pe.file()
                            << " at line " << pe.line() << ", position " << pe.pos() << '\n';
                    }
                    
                    try {
                        f->close();
                        delete f;
                    }
                    catch (Eception &e) {
                        std::cerr << "I'm already finished ;).\n";
                    }
                    

                    statt

                    try {
                        FileOfSpecificType f(filePathAndName);
                    
                        objects = f.parse();
                    
                        f.close();
                    }
                    catch (IOError &ioe) {
                        std::cerr << "Could not parse " << filePathAndName << ": "
                            << ioe.what() << '\n';
                    }
                    catch (SecurityException &se) {
                        std::cerr << "Permission denied: " << filePathAndName << '\n';
                    }
                    catch (MemoryError &me) {
                        std::cerr << "Could not allocate enough memory for parsing " << filePathAndName
                            << ": " << me.what() << '\n';
                    }
                    catch (ParserException &pe) {
                        std::cerr << "Unexpected token " << pe.token() << " in " << pe.file()
                            << " at line " << pe.line() << ", position " << pe.pos() << '\n';
                    }
                    

                    Also ich sehe da nicht den Vorteil der oberen Lösung. Welcher soll es sein?

                    Viele Grüße
                    Robert

              2. Hallo pl,

                Denn das hieße ja, daß man spätestens beim Erstellen der 2. Exceptioninstanz die 1. Exception ignoriert hat!

                Wer Exceptions nicht fängt, dem wird von der Runtime standrechtlich der Thread gecancelled. Wer sie fängt und ignoriert, ist selbst schuld.

                Eine Exception-Instanz ist eine Nachrichtenkapsel. Sie wird gefüllt, fallen gelassen (throw) und fällt dann solange am Callstack entlang bis jemand mit einem Netz bereit steht. Wenn er sich zuständig fühlt (catch mit ClassName), fängt er sie weg, macht die Kapsel auf und liest die Nachricht. Danach kann er sie in den Müll werfen (vom Garbage Collector deallocieren lassen) oder die Kapsel wieder zumachen und fallen lassen (rethrow, Stacktrace bleibt). Statt dessen kann er die Kapsel auch in eine neue Kapsel stecken, einen Zettel dazulegen und die größere Kapsel rauswerfen (InnerException). Fühlt sich keiner zuständig, fällt sie durch bis auf die Grundplatte (Laufzeitumgebung), löst Alarm aus und beendet das Programm.

                Entscheidend ist aber: Wenn die Exception nicht weiter geworfen wird, wird das Objekt vom Exceptionhandling deallociert. Das geschieht in den meisten Sprachen automatisch. Du kannst es für eine neue Exception gar nicht verwenden, bei der nächsten Exception wird ein neues Objekt erzeugt.

                In Perl ist das - wenn ich das richtig verstehe - anders. Um Exceptions zu fangen brauchst Du einen eval-Block, und der baut gnadenlos einen Trichter namens $@ auf, in dem jede Exception landet. Eine Exception nicht zu fangen ist überhaupt nicht möglich. Du kannst sie nur weiterwerfen. Und ob Du das Exception-Objekt deallocierst, bleibt Dir überlassen. Wenn nicht, liegt es in $@ herum bis die nächste Exception die Referenz überschreibt und dem Garbage Collector freie Hand gibt.

                Hier ist wohl der Haupt-Unterschied zwischen Perl und vielen anderen Sprachen: In Perl musst Du zugreifen, in C# oder PHP kannst Du die Exception vorbeirauschen lassen.

                In PHP oder C# ist es von der Gültigkeit her so:

                try {
                   callFunc();
                }
                catch (InvalidArgumentException x) {
                   // behandeln
                }
                
                function callFunc() {
                   throw new InvalidArgumentException("Ätsch");
                }
                

                Das Exception-Objekt existiert in callFunc() nur temporär. Es wird erzeugt, geworfen und keine Referenz darauf gespeichert. Man KÖNNTE anderes tun, man KÖNNTE ein Exception-Objekt an anderer Stelle speichern oder in eine Closure stecken, aber sowas tut man nicht. Man belässt die Referenz schön beim Auslöser auf dem Stack.

                Nachdem die Exception geworfen wurde, hält das Exception-Handling die Referenz auf das Exception-Objekt und räumt solange Stackframes ab, bis ein passender catch dazwischen kommt. Jetzt wird das Exception-Objekt an den Parameter von catch zugewiesen, und der hat nun die Verantwortung dafür. Das Exception-Handling gibt seine Referenz frei.

                Was nach Ende des Catch-Block passiert hängt von der Sprache ab. C# hat ein striktes Blockkonzept, wird der Catch-Block verlassen ist das Objekt referenzfrei und kann collected werden. In PHP nicht, da lebt es nach dem catch noch und wird - sofern man es nicht speichert - am Ende der Funktion dem GC zum Fraße vorgeworfen. Ist man in keiner Funktion, lebt es bis zum Script-Ende...

                Rolf

                --
                sumpsi - posui - clusi
                  1. Hallo,

                    [Antwort]

                    Wow.

                    Auf einen Beitrag, in dem nicht eine einzige Frage drin vorkommt, der aber gefühlt den Umfang eines halben Romans hat, sich der Schreiber also recht viel Mühe gegeben hat, mit nur einem nichtsagenden, unkommentierten Link zu reagieren, ist extrem dreist.

                    Gruß
                    Kalk

          3. Moin,

            Vermutlich wird unter der Haube eine Klassenvariable gesetzt.

            Es wird ein Objekt der Klasse erzeugt.

            Auf jeden Fall steckt eine statische Variable dahinter, welche den Fehlertext beeinhaltet.

            Nö:

            1. ist es keine statische Variable.
            2. Muss die Variable keinen Text enthalten. Mein Beispiel funktioniert auch „in günstig“:
            class ArithmetischerFehler {};
            
            class DivisionDurch0 : public ArithmetischerFehler {};
            

            Objekte dieser beiden Klassen haben per Definition in C++ eine Speichergröße von 1 Byte:

            std::cout << sizeof(ArithmetischerFehler) << ' ' << sizeof(DivisionDurch0) << '\n';
            // gibt aus:
            // 1 1
            

            Ansonsten kann jede Exception-Klasse die Attribute definieren, die sie benötigt; eine Parser-Exception z.B. das falsche Token, Dateiname, Zeilennummer und Zeichenposition.

            Die Frage ist, welchen Vorteil es bringt, anstatt eines Fehlertextes an throw() eine Klassenmethode bzw. den Namen einer Klasse zu übergeben? Womit wahrscheinlich sogar eine Instanz erzeugt wird, aber wozu?

            Ich möchte im Fehlerfall nicht erst einen Fehlertext zusammenstellen und im catch-Block wieder auseinander nehmen müssen – vor allem, wenn wie oben gezeigt gar kein Fehlertext nötig ist.

            Viele Grüße
            Robert

            1. Nun, wenn beim Wurf eine EX kein Fehlertext übergeben wird, muss er ja statisch sein. Denn er muss ja irgendwo herkommen. Du übergibst mit throw DivisionDurch0; lediglich den Namen einer Klasse.

              Mit throw std::Rechenfehler("Division durch null!") hingegen ist die Sache klar.

              1. Moin,

                Nun, wenn beim Wurf eine EX kein Fehlertext übergeben wird, muss er ja statisch sein. Denn er muss ja irgendwo herkommen.

                Nein, mein „Rechen“-Beispiel kommt ohne Fehlertext aus – mindestens im zweiten Fall. Da ist es auch vollkommen egal, ob der Compiler intern die Klassen anders bezeichnet („Name Mangling“).

                Du übergibst mit throw DivisionDurch0; lediglich den Namen einer Klasse.

                Nein, es wird ein Objekt dieser Klasse erzeugt.

                Mit throw std::Rechenfehler("Division durch null!") hingegen ist die Sache klar.

                … solange man

                • der deutschen Sprache mächtig ist,
                • keine Exceptionhierarchien nutzen möchte
                • und Performance für irrelevant hält:
                  • In deinem Fall werden mindestens 21 Byte und ein Stringvergleich benötigt.
                  • In meinem Fall wird 1 Byte und ein Typvergleich – das kann auch über einen Typcode laufen – benötigt.

                Viele Grüße
                Robert

                1. Moin,

                  Du übergibst mit throw DivisionDurch0; lediglich den Namen einer Klasse.

                  Nein, es wird ein Objekt dieser Klasse erzeugt.

                  Stimmt natürlich. Was aber die Frage wozu auch nicht beantwortet.

                  MfG

                  1. Moin,

                    das beantwortet die Frage sehr wohl, man sollte vielleicht auch die ganze(n) Antwort(en) lesen und verstehen. Die Beispiele schreibe ich für dich, nicht für mich.

                    Viele Grüße
                    Robert

                2. Tach!

                  Mit throw std::Rechenfehler("Division durch null!") hingegen ist die Sache klar.

                  … solange man

                  • der deutschen Sprache mächtig ist, [...]
                    • In deinem Fall werden mindestens 21 Byte und ein Stringvergleich benötigt.

                  Das ist auch ein wesentlicher Punkt. Wenn man ein Framework hat, das Texte in lokalisierter Form erstellt, dann läuft das Programm nur in einer Region, wenn man auf einen Stringvergleich baut. Der Klassenname hingegen ist immer eindeutig, egal welcher Text erzeugt wurde.

                  Zudem kann der Text auch unterschiedlich ausfallen, à la "Datei %s nicht gefunden." Und nun mach mal einen Stringvergleich, um die Exception zu fangen. Die FileNotFoundException ist hingegen immer von derselben Klasse, ganz unabhängig vom Dateinamen im Text.

                  dedlfix.

                  1. Die Frage der Sprache ist nur dann relevant wenn eine Meldung an den Benutzer geht. Was aber nicht die Sache eines Exception Objekts ist sondern in den Zuständigkeitsbereich des GUI fällt.

                    Und da ist sie wieder, meine Frage: Was wäre denn der Vorteil der Übergabe einer EXinstanz an die GUIinstanz anstelle einer Fehlernummer?

                    MfG

                    1. Moin,

                      Die Frage der Sprache ist nur dann relevant wenn eine Meldung an den Benutzer geht. Was aber nicht die Sache eines Exception Objekts ist sondern in den Zuständigkeitsbereich des GUI fällt.

                      Dann ist dein Beispiel irreführend.

                      Und da ist sie wieder, meine Frage: Was wäre denn der Vorteil der Übergabe einer EXinstanz an die GUIinstanz anstelle einer Fehlernummer?

                      Und da ist sie wieder, meine Antwort mit einem Beispiel, was alles an einem Exception-Objekt hängen kann.

                      Viele Grüße
                      Robert

                      1. Dein Beispiel in Ehren aber es zeigt ja keinen Vorteil. Und alles in englisch auzugeben ist auch kein Vorteil von OOP.

                        Um mal einen Schnitt zu tun: OOP ist weder ein Dogma noch die Lehre der Entstehung der Arten. Vielmehr ist OOP eine praktische Angelegenheit. Und eigentlich nur eine Art und Weise wie man seinen Code zweckmäßig organisiert.

                        Wesentlich an OOP ist, daß Instanzen von Klassen erstellt werden, die deswegen Instanzen sind weil sie wissen zu welcher Klasse sie gehören und damit ihren Namespace kennen sowie die Methoden die sie aufrufen dürfen. Dafür tragen Instanzen Eigenschaften mit sich rum die sehr komplex sein können.

                        OOP ist schon das da:

                        my $obj = {
                            name => 'Huber',
                            vname => 'Wastl' 
                        };
                        
                        sub showname{
                            my $self = shift;
                            print $self->{name};
                        }
                        
                        showname($obj);
                        

                        Aber richtig interessant wirds wenn das Objekt den Namen seiner Klasse kennt:

                        bless $obj;
                        $obj->showname();
                        

                        Womit man zum Aufruf der Methoden den -> Operator nehmen kann, der nichts weiter tut als die aufrufende Instanz als 1. Argument zu übergeben. In c++, so habe ich das auch mal gelernt, wird eine Instanz mit new() erstellt. Ebenso erstellt aber auch throw() eine neue Instanz. Nämlich der Klasse die da übergeben wird. Allein aus diesem Sachverhalt jedoch ergibt sich kein Vorteil in Sachen EXns.

                        MfG

                        1. Moin,

                          Dein Beispiel in Ehren aber es zeigt ja keinen Vorteil.

                          Dann mal Butter bei die Fische: Wenn das ParserException-Objekt keinen Vorteil zu einem Fehlercode darstellt, dann zeig doch mal bitte deine Lösung für das von mir geschilderte Beispiel. Kritisieren kann jeder, konstruktive Kritik fehlt meist.

                          Und alles in englisch auzugeben ist auch kein Vorteil von OOP.

                          Darauf zielt auch keines meiner Beispiele ab. Die ggf. (!) auszugeben Fehlermeldungen können auch auf klingonisch sein.

                          Vielmehr ist OOP eine praktische Angelegenheit. Und eigentlich nur eine Art und Weise wie man seinen Code zweckmäßig organisiert.

                          Meine Beispiele zeigen sehr deutlich, wie man mit Hilfe von OOP Code praktisch und zweckmäßig organisieren kann.

                          Wesentlich an OOP ist, daß Instanzen von Klassen erstellt werden, die deswegen Instanzen sind weil sie wissen zu welcher Klasse sie gehören und damit ihren Namespace kennen sowie die Methoden die sie aufrufen dürfen. Dafür tragen Instanzen Eigenschaften mit sich rum die sehr komplex sein können.

                          Klassen können auch abgeleitet sein und das Objekt weiß das dann auch. Und genau das lässt sich im Exceptionhandling sehr praktisch ausnutzen.

                          In c++, so habe ich das auch mal gelernt, wird eine Instanz mit new() erstellt. Ebenso erstellt aber auch throw() eine neue Instanz. Nämlich der Klasse die da übergeben wird.

                          throw (ohne Klammern!) erzeugt nicht zwingend eine neue Instanz:

                          struct SimpleException {
                          	SimpleException(const int code) : _err(code) {}
                          
                          	int _err;
                          };
                          
                          SimpleException se(42);
                          
                          try {
                          	throw se;
                          }
                          catch (SimpleException &ex) {
                          	std::cout << "einfache Exception mit Fehlercode " << ex._err << " gefangen.\n";
                          }
                          

                          Allein aus diesem Sachverhalt jedoch ergibt sich kein Vorteil in Sachen EXns.

                          Das ist ja auch nicht der einzige Aspekt, der für Exception-Objekte spricht.

                          Viele Grüße
                          Robert

                    2. Tach!

                      Die Frage der Sprache ist nur dann relevant wenn eine Meldung an den Benutzer geht.

                      Der Entwickler ist auch ein Benutzer: ein Benutzer des Frameworks. Nicht jeder kann Englisch, und so gibt es Frameworks, beispielsweise .NET, die lokalisiert daherkommen und Fehlermeldungen in anderen Sprachen als Englisch erzeugen. Die Sprache ist sogar unabhängig vom Entwickler, denn das Framework ist auf den Rechnern der Anwender installiert und dort üblicherwiese lokalisiert. Die Sprache ist also mitnichten generell irrelevant oder nur eingeschränkt relevant.

                      Zudem geht jede Meldung an den Endbenutzer, die nicht gefangen wurde. Falls mal einen generellen Fangmechanismus eingebaut hat und nicht nur "Es ist ein unbekannter Fehler aufgetreten" an die Front werfen möchte, hat man auch ein Problem mit der Übersetzung des konkreten Vorfalls.

                      Was aber nicht die Sache eines Exception Objekts ist sondern in den Zuständigkeitsbereich des GUI fällt.

                      Das magst du so sehen, die Welt sieht aber anders aus.

                      Und da ist sie wieder, meine Frage: Was wäre denn der Vorteil der Übergabe einer EXinstanz an die GUIinstanz anstelle einer Fehlernummer?

                      Nummern sind nichtssagend, Klassennamen sind sprechender.

                      dedlfix.

                      1. Nummern sind nichtssagend, Klassennamen sind sprechender.

                        Was soll den ein Benutzer mit einem Klassennamen anfangen?

                        Ganz bestimmt nicht wird man einem Benutzer weder das eine noch das andere zeigen!

                        1. Moin,

                          wenn du schon antwortest, dann sollte deine Antwort wenigstens den Eindruck haben, dass du das Posting, auf das du antwortest, komplett gelesen hast.

                          Was soll den ein Benutzer mit einem Klassennamen anfangen?

                          Die Antwort auf diese Frage steht in dedlfix' Beitrag, auf den du diese Frage stellst. dedlfix hat zuvor geschrieben:

                          Der Entwickler ist auch ein Benutzer

                          Viele Grüße
                          Robert

                        2. Tach!

                          Nummern sind nichtssagend, Klassennamen sind sprechender.

                          Was soll den ein Benutzer mit einem Klassennamen anfangen?

                          Du hast dich nicht auf den Nutzer bezogen, sondern auf die GUIInstanz und damit auf den Entwickler. Code wird mit Nummern nicht verständlicher.

                          dedlfix.

            2. Ansonsten kann jede Exception-Klasse die Attribute definieren, die sie benötigt; eine Parser-Exception z.B. das falsche Token, Dateiname, Zeilennummer und Zeichenposition.

              Hervorragendes Beispiel, das merk ich mir.

              1. Moin

                Danke :)

                Die Idee kam mir aus dem XML-Umfeld, vermutlich, als ich mit xmlwrapp gearbeitet habe.

                Viele Grüße
                Robert

          4. Aloha ;)

            Die Frage ist, welchen Vorteil es bringt, anstatt eines Fehlertextes an throw() eine Klassenmethode bzw. den Namen einer Klasse zu übergeben? Womit wahrscheinlich sogar eine Instanz erzeugt wird, aber wozu?

            Diese Frage ist für mich viel sinnhafter als die ursprüngliche.

            Ich versuche dir mal zu antworten:

            Auf den ersten Blick hast du Recht, ein Fehlertext genügt oft. Oder um noch weiterzugehen: Eine Fehlernummer reicht in diesen Fällen auch.

            Die Objektorientierung als Eigenschaft der Sprache ist kein Argument, soweit will ich dir Recht geben - natürlich ist das ein Argument, wenn es darum geht, warum in dieser Sprache Fehler als Objekt abgebildet werden, es ist aber kein Argument dafür, das woanders ähnlich zu handhaben.

            Warum dann ein Fehlerobjekt? Schauen wir dazu mal in die Java-Klasse Throwable aus der alle Java-Fehler abgeleitet sind. In dieser allgemeinsten Fehlerklasse gibt es unter anderem folgende Methoden:

            • getMessage()
            • getStackTrace()

            Erstere liefert das, was auch bei Rückgabe eines Fehlertextes erreicht wäre. Aber schon Zweiteres kann ein einfacher Fehlertext nicht mehr: Angeben, an genau welcher Stelle des Programms der Fehler aufgetreten ist, und welche Funktionsaufrufe dahin geführt haben. Es ist also offensichtlich so, dass aus Sicht der Java-Autoren zu einem Fehler nicht nur ein beschreibender Text, sondern eben auch ein Stacktrace gehört - und diese beiden müssen natürlich, wenn sie zusammengehören, auch in ein entsprechendes Objekt gekapselt werden.

            Wenn man nun aus dieser allgemeinen Fehler-Klasse spezialisierte Fehler-Klassen ableitet, erhält man dann sogar die Möglichkeit, diesem spezialisierten Objekt noch weitere beschreibende Eigenschaften mitzugeben. So könnte zur Fehlerbehandlung bei einer nicht-existierenden Datei der Dateipfad im Exception-Objekt gespeichert sein, damit dieser zur Fehlerbehandlung sofort zur Verfügung steht. Viele weitere Beispiele sind denkbar, bei denen eine abgeleitete Fehlerklasse sinnvoll erweitert wird.

            Das aber wiederum ist nur bei einer Repräsentation als Objekt sinnvoll möglich - nicht in einem String, auch nicht in einer anderen fixen Datenstruktur. Allenfalls in einer Datenstruktur, die genügend objektartige Eigenschaften hat, d.h. hinreichend beliebige, eindeutig identifizierbare Felder aufnehmen kann. In Haskell, das keine Objekte kennt, sind Exceptions durch eine entsprechende Data declaration definiert, denen auch geordnete Argumentlisten mitgegeben werden können.

            Grüße,

            RIDER

            --
            Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
            # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
            1. Moin,

              um es mal so zu formulieren: Man kann sich ja vorher überlegen welche EX zu erwarten und zu fangen ist! So steht nämlich fest, wie man damit umzugehen hat und dafür braucht man keine Exceptionklassen. Nicht die Exception bestimmt was man mit ihr macht sondern eine übergeordnete Instanz bestimmt das.

              Schließlich ist eine abgerauchte Datenbankverbindung nicht die Folge einer fehlerhaften Benutzereingabe. Und ein diesbezüglich nachgelagerter Eskalationsprozeß braucht keine Klasseninstanzen sondern Informationen die er per SMS//Mail weiterleitet.

              MfG

              1. Moin,

                man kann sich auch vorher überlegen, an welchen Stellen man wie auf eine Exception reagiert – und dabei helfen Exception-Objekte und -Hierarchien ungemein. Details dafür findest du zu Hauf in dieser Diskussion.

                Viele Grüße
                Robert

              2. Aloha ;)

                um es mal so zu formulieren: Man kann sich ja vorher überlegen welche EX zu erwarten und zu fangen ist! So steht nämlich fest, wie man damit umzugehen hat und dafür braucht man keine Exceptionklassen. Nicht die Exception bestimmt was man mit ihr macht sondern eine übergeordnete Instanz bestimmt das.

                Klar. Man kann für alles einen verschwurbelten Workaround handstricken.

                Du hattest nach der Sinnhaftigkeit gefragt. Die wird nicht dadurch widerlegt, dass man das Problem auch unsinnvoll lösen kann.

                Grüße,

                RIDER

                --
                Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
            2. PS:

              es gibt auch klassenlose Datenstrukturen. Die gibts in c als stuct und in JavaScript heißen die soagr Objekte. Und in Perl ntürlich gibt es die auch:

              
              use base 'DB';
              die {
                 de => 'ungülig',
                 en => 'invalid',
                 backtrace => __PACKAGE__->backtrace(),
                 etc..
              };
              

              findet man in der catchFraktion genauso wieder wie einfache Literale. Und auch solche Objekte können sehr vielgestaltig sein!

              .

              1. Moin,

                in C++ ist eine Struktur eine Klasse, mit dem Unterschied, dass in einer struct per Default alle Member public sind und in einer class per Default private. Folgende Konstrukte sind daher äquivalent:

                struct Klasse {
                private:
                    // …
                };
                
                class Klasse {
                    // …
                };
                

                sowie

                class Struktur {
                public:
                    // …
                };
                
                struct Struktur {
                    // …
                };
                

                Viele Grüße
                Robert

                1. Ja. Was ist denn eigentlich ein Objekt, was eine Instanz und wozu gibt es überhaupt Klassen? Die Antwort kann man allgemein verfassen:

                  Objekte referenzieren Datenstrukturen wie z.B. Arrays. Erst die Klassenzugehörigkeit macht ein Objekt zu einer Klasseninstanz und befähigt es, Methoden aufzurufen welche die Klasse definiert.

                  Diese Definition findest Du auch in c++ u.a. Programmiersprachen wieder. Perl ab v5 macht genau diese Definition sehr anschaulich:

                  $object = {};  # HashRef
                  foo($object);  # an Funktion übergeben
                  
                  # wenn das Objekt selbst die Funktion aufrufen soll
                  # muss es den Namen seiner Klasse kennen
                  bless $object, 'main';
                  
                  # und nun darf es die Funktion selbst aufrufen
                  # dabei übergibt es sich selbst
                  $object->foo();
                  

                  Das Ergebnis ist dasselbe, in beiden Fällen findet eine Übergabe statt. So kann innerhalb der Funktion auf die HashRef zugegriffen werden, die gewöhnlich $this oder $self genannt wird.

                  Natürlich kann man einer Exception auch komplexe Datenstrukturen zum letzten Geleit mitgeben. Und natürlich dürfen das auch Instanzen sein, die in dem Moment erstellt werden wenn der Kamerad stirbt.

                  Nur stellt sich dann die Frage warum es eine Instanz sein muss. Antwort siehe oben: Wenn es darum geht, mit dieser Instanz Methoden aufzurufen. Oder um bestimmte Dinge automatisieren zu können. Z.B. wird der Destruktor ja auch zwangläufig gerufen beim Tod einer jeden Instanz. Darin könnte sich dann auch ein Exception-Objekt verewigen wenn es seinen lezten Seufzer tut.

                  Der Möglichkeiten gibt es eben viele in OO. Genausogut gibt es die aber auch ohne.

              2. Aloha ;)

                es gibt auch klassenlose Datenstrukturen. Die gibts in c als stuct und in JavaScript heißen die soagr Objekte.

                Klar. Nur kann sich dann keiner drauf verlassen, dass ein irgendwo geworfenes Objekt tatsächlich die erwartete Struktur hat. Deshalb hat man ja überhaupt Klassen und Typisierung: Um sicherzustellen, dass Objekte einer festgeschriebenen Form folgen.

                Und wie ich bereits schrieb: Du kannst das zwar auch anders machen, aber dann isses halt scheiße.

                Grüße,

                RIDER

                --
                Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
      3. Moin,

        noch ein zweites Beispiel (wieder C++): Bei einem Windows-Programm können verschiedene Laufzeitfehler auftreten, also z.B. von C++ oder von Windows. Diese APIs haben ihre eigenen Funktionen den Laufzeitfehler zu ermitteln und als Fehlertext auszugeben. Aber es sind beides Laufzeitfehler, also abgeleitete Klassen davon. Ich kann nun in den Konstruktoren der Fehlerklassen den Fehlertext ermitteln, während der Aufrufer nur den Laufzeitfehler fangen muss:

        class CppError : public std::runtime_error {
        public:
            CppError()
            : std::runtime_error(std::strerror(errno))
            {
            }
        };
        
        class WindowsError : public std::runtime_error {
        public:
            WindowsError()
            : std::runtime_error(/* Funktion zur Ermittlung des Windowsfehlertexts */)
            {
            }
        };
        
        
        // Im Programm:
        try {
            funktionsAufruf(/* … */);
        }
        catch (std::runtime_error &re) {
            // …
        }
        

        Viele Grüße
        Robert

        1. Das kann man in Perl auch machen: throw() als Konstruktor einer eigenen Fehlerklasse. Die Frage ist jedoch wozu das gut sein soll?

          throw Error::Simple( "A simple error");

          1. Moin,

            wie fängst du denn dann in Perl den Laufzeitfehler, der eigentlich ein Objekt einer abgeleiteten Klasse ist?

            Viele Grüße
            Robert

    2. Das ist wie bei jeder Art von Objekten: Zusammenfassung von Datenfeldern und Methoden zu einer Einheit.

      Vermisse ich schmerzlich auf HTML Seiten. Ich setze die nach dem Baukasten-System zusammen. So bekommt ein Festival etwa die Teilnehmerliste angehängt, die ein normales Event nicht hat.

      Firefox akzeptiert zwar sowas

      <section id="teilnehmer">
        <style>
        #teilnehmer {border:1px solid #f00;padding:5px;}
        </style>
        ... 
      </section>
      

      aber der Validator bezeichnet style unter section als Fehler. Da kann ich also nicht sicher sein, ob andere Browser das auch akzeptieren.

      Klar könnte ich den anteiligen style auch im head unterbringen, aber das ist doch so bescheuert wie Tisch decken, die Gabeln liegen in der Küche und die Messer einen Stock höher im Schlafzimmer.

      Gruß, Linuchs

      1. Hallo Linuchs,

        <section id="teilnehmer">
          <style>
          #teilnehmer {border:1px solid #f00;padding:5px;}
          </style>
          ... 
        </section>
        

        Klar könnte ich den anteiligen style auch im head unterbringen,

        Warum nicht in deiner CSS-Datei??

        Bis demnächst
        Matthias

        --
        Pantoffeltierchen haben keine Hobbys.
        1. Warum nicht in deiner CSS-Datei??

          Wir schreiben hier über Objekte. Daten und Methoden bzw. Strukturen bilden eine Einheit. Das in mehreren Dateien zu splitten ist unübersichtlich.

          Und wer weiß denn noch nach ein paar Jahren und 100 Webseiten, welche Einträge in der CSS-Datei wirklich gebraucht werden?

          1. Hallo Linuchsx,

            Und wer weiß denn noch nach ein paar Jahren und 100 Webseiten, welche Einträge in der CSS-Datei wirklich gebraucht werden?

            Wenn du für 100 Projekte dieselbe CSS-Dateie verwenden möchtest …

            Ansonsten schlummern in jeder CSS-Datei ungenutzte Deklarationen, weil nicht jede Seite eines Projektes denselben Aufbau hat.

            Bis demnächst
            Matthias

            --
            Pantoffeltierchen haben keine Hobbys.
            1. Hallo Matthias,

              Ansonsten schlummern in jeder CSS-Datei ungenutzte Deklarationen, weil nicht jede Seite eines Projektes denselben Aufbau hat.

              abgesehen davon, dass ich Linuchsx Argumentation ziemlich abwegig finde, ist Append-Only-CSS in größeren Projekten ein echtes Problem. Deshalb hat man ja erst angefangen mit BEM, Styled Components, usw, pp.

              LG,
              CK

  2. Hallo,

    du musst dir überlegen, was die Alternative zu exceptions sind. Eine Exception transportiert im Wesentlichen 2 Dinge: der Grund oder wenigstens die Kategorie des Fehlers (i.d.R. durch die Klasse ausgedrückt) und eine Payload, die die Begleitumstände beschreiben kann.

    Wichtig: die Payload kann für jeden Fehler unterschiedlich sein. Nehmen wir mal eine Funktion, die einen HTTP-Call irgendwohin macht. Mögliche Exceptions wären sowas wie HostNotFoundException (Domain nicht auflösbar), NetworkException (es kommt keine Netzwerk-Verbindung zustande), AuthorizationException (konnte nicht authorisieren), diverse HTTPError (z.B. HTTP-Request liefert Status 400, 500, 404) und zu guter letzt noch Parsing-Fehler beim Inhalt (d.h. der Body entspricht nicht dem, was der Client erwartet, z.B. kein gültiges JSON).

    Die "normale" Implementierung ohne Exception macht das über Rückgabewerte. D.h. zusätzliche zum eigentlichen Rückgabewert gibt die Funktion noch einen Statuscode zurück. In golang z.B. i.d.R. erster Returnwert Status, zweiter Returnwert dann der eigentliche Wert der Funktion (in unserem Beispiel also die Response des HTTP-Calls).

    Da wir noch eine Payload haben wollen (z.B. der HTTP-Body, damit wir ihn später loggen können), brauchen wir schon drei Rückgabewerte: Status-Code, Payload, eigentlicher Funktionsreturn.

    Dann stossen wir schnell auf das Problem, dass für verschiedene Status die Payload unterschiedlich ist. Wenn man eine Sprache mit Superklasse oder ähnliches (stdclass, Object, void*) nutzt, muss man das dann nutzen. In anderen müssen die Payloads schon von einer gemeinsamen Basisklasse erben um ein wenig Typsicherheit zu erreichen.

    Wenn ich dann eine solche Funktion aufrufe, sieht das dann so aus:

    int statusCode; Object exceptionPayload; MyType returnValue;
    (statusCode, exceptionPayload, returnValue) = myFunction(param1, param2);
    
    if (statusCode == FEHLER_CODE_1) {
       doSomethingWithPayload(exceptionPayload);
    } else if (statusCode == FEHLER_CODE_2) {
       doSomethingElseWithPayload(exceptionPayload);
    } else {
       // hey, happy path!
       doSomethingWithReturnValue(returnValue);
    }
    

    und das für jeden einzelnen Funktionsaufruf. Und hier habe ich schon eine golang-ähnliche Syntax verwendet. Andere Sprachen, die nicht mehrere Returnwerte kennen, müssen dann entweder Referenzen als Outputparameter nutzen oder eigene Returntypen schreiben.

    Exceptions machen das zunächst mal einfacher.

    1. Exceptions bündeln Status Code und Exception Payload.
    2. Exceptions bubbeln den Call-Stack automatisch nach oben, wenn sie nicht gefangen werden. (Bei Funktionsaufrufen musst du jeden einzelnen Funktionscall separat prüfen).
    3. m.E. ist der Happy-Path (der Code-Pfad, in dem nichts schief läuft) einfacher zu lesen. Fairerweise sei erwähnt: der Code-Pfad, in dem etwas schiefläuft, wird dadurch schwieriger zu lesen, insb. wenn man bubbeln lässt; dieser lässt sich dann nicht mehr linear lesen.

    Viele Grüße Matti

    1. Hallo,

      du musst dir überlegen, was die Alternative zu exceptions sind.

      Aber gerne. Nur ist das nicht die Frage hier!

      MfG

      1. Ernsthaft? Ich investiere 20min, nehme deine Frage ernst statt dir ein lmgtfy um dir Ohren zu hauen, gebe dir eine detaillierte Antwort, und dann hängst du dich ein einem Satz auf mit der Unterscheidung Exception und ExceptionObject.

        Danke, das war es. Dir habe ich die letzte Antwort gegeben.

        plonk

  3. Hallo pl,

    eigentlich hast Du alles genannt bekommen:

    • sauberere Datenorganisation
    • Polymorphie bei der Fehlerbehandlung
    • Klassifikationsmöglichkeit der Fehlerursache

    Gerade zum letzten Punkt gerne noch ein Beispiel: Bei uns im Unternehmen verwenden wir eine Middleware, um aus C# Programmen auf unseren Großrechner zuzugreifen. Wenn es dabei zu Problemen kommt, gibt es eine Exception. Eine davon ist speziell, sie sagt mir: Das hat länger gedauert als Du warten wolltest. Eine andere sagt mir: Dein User darf diesen Service aber gar nicht nutzen. Und noch andere: Da ist Schrott in der Servicedefinition, der Service ist platt, der Message Queue Dienst ist im Eimer - jede Menge.

    Bei den meisten reicht der Meldungstext, klar. Aber die Reaktion ist trotzdem verschieden:

    • Schrott, Service platt, MQ im Eimer -> ich kann gar nichts mehr tun, der Anwender muss warten bis das System wieder läuft
    • Recht fehlt: Kann man ausnutzen um zu unterscheiden, was der Mensch eigentlich tun darf.
    • Timeout: Hier bekomme ich als zusätzliches Property einen AsyncKey, also eine Objektreferenz, mit dem ich einen Lookup-Call machen kann, um - ggf. nach Rückfrage an den Anwender - länger zu warten.

    Das Ganze passiert dann auf einem Webserver-Pärchen, das eben mal 5000 Anwender bedient, also locker 100 Requests pro Sekunde abarbeiten muss. Das passiert in etlichen Threads parallel auf einem Multicore-Server. Da ist nichts mit statischen Variablen, alles muss auf Stack oder Heap liegen. Ohne Exception-Objekte bekäme ich Kontextinformationen zu ausgelösten Exceptions nicht durch den Callstack nach oben.

    Und durch die Typen der Exception-Objekte kann ich im catch schon kategorisieren. Zusammen mit when kann ich erreichen, dass überhaupt nicht erst gefangen wird, wenn die Bedingung falsch ist (was beim Stacktrace einen Unterschied macht).

    try {
       var result = fooService.BarMethod(x,y,z);
       // result verarbeiten
    }
    catch (TimeoutException te) when te.RetryCount < 3 {
       // Spezielle HostAccessException bei Timeout, ggf. mittels te.AsyncKey weiter warten
       // where-Option fängt die Exception nur wenn re
    }
    finally {
       // Abräumen etc
    }
    

    Rolf

    --
    sumpsi - posui - clusi
    1. @Rolf B

      eigentlich hast Du alles genannt bekommen:

      • sauberere Datenorganisation
      • Polymorphie bei der Fehlerbehandlung
      • Klassifikationsmöglichkeit der Fehlerursache

      Ja sicher doch. Nur kriegt man das auch ohne Exceptionklassen gebacken. Ein Vorteil ist da nicht erkennbar. Zumal es kein Beispiel hierfür gibt.

      MfG

      1. Hallo pl,

        Nur kriegt man das auch ohne Exceptionklassen gebacken

        Spätestens wenn Du Objektreferenzen mit einer Exception mitliefern musst ist es vorbei. Wie oben in meiner User Story erzählt: statische Variablen sind ein No-Go. In Perl geht's vielleicht, wenn jeder Request in einem eigenen Adressraum verarbeitet wird. Aber in Highperformance-Systemen macht man das nicht.

        Rolf

        --
        sumpsi - posui - clusi
        1. @Rolf B

          Nur kriegt man das auch ohne Exceptionklassen gebacken

          Spätestens wenn Du Objektreferenzen mit einer Exception mitliefern musst ist es vorbei.

          Genau das kann man in Perl sehr gut machen: Objektreferenzen erzeugen. Selbstverständlich auch beim Wurf einer EX.

          MfG

  4. Auch mehrsprachige Exceptions sind kein Grund für dedizierte Klasseninstanzen.

    Per HTTP_ACCEPT_LANGUAGE wird hier der Inhalt bzw. die Sprache für die Fehlermeldungen über Exceptions ausgehandelt.

    Default ist de insgesamt ist jedoch noch nicht jede Meldung 2 sprachig. Wer das mal testen will, en, de ist auch hier bereits drin.

    MfG

    1. Moin,

      Auch mehrsprachige Exceptions sind kein Grund für dedizierte Klasseninstanzen.

      das hat auch niemand behauptet, wir sprachen von sprachneutralen Exceptions.

      Viele Grüße
      Robert

      1. Nun, ich nutze hier das Exception Modell für die Fehlerbehandlung was die Ausgabe einer für den Benutzer verständlichen Fehlermeldung mit einschließt. Sprachneutral kann man höchstens innerhalb seiner Klassen bleiben.

        Was Exceptions zur Fehlerbehandlung betrifft, ist zu entscheiden ob die ein Nutzer verursacht oder ob der Programmierer den Code einer Klasse falsch verwendet. Das kann man in Modulen die für die Allgemeinheit bestimmt sind nicht machen, wohl aber in eigenen Entwicklungen wie das Beispiel zeigt. Und für ein falsches Datum gibt es sehr viele Möglichkeiten zumal 2 Kalender im Spiel sind.

        Hier lege ich den ganzen Code offen um das mal zu zeigen wie sowas den Anwendungs Code extrem vereinfacht.

        In CPAN Modulen ist Carp empfohlen was jede EX mit einem Trace dekoriert.

        Es gibt in Perl übrigens noch weitere Möglichkeiten, den Trace bedarfsweise (und zentral!) ein oder auszuschalten, was hier ja auch angesprochen wurde.

        .

        1. Moin,

          das ist ja alles schön und gut, aber ich klinke mich erst wieder hier ein, wenn es nicht mehr um Perl geht, sondern um OOP allgemein. Ich habe meine ganzen Beispiele nicht gebracht, damit du an ihnen vorbeiargumentierst.

          Schönen Abend,
          Robert

          1. das ist ja alles schön und gut, aber ich klinke mich erst wieder hier ein, wenn es nicht mehr um Perl geht, sondern um OOP allgemein.

            So!? Deine Beispiele sind mitnichten allgemein sondern in c++ !

            1. Ach Gottchen,

              als richtiger Entwickler(TM) weißt du bestimmt, dass das in Java, C#, Python, Delphi kaum anders aussähe. Den Beweis überlasse ich dir, weil du meine Beispiele eh nicht liest. Mir platzt echt der Kragen.

              Grüße
              Robert

    2. Hallo pl,

      Antwort

      können wir das Thema jetzt ruhen lassen? Meinungen hast Du gehört, und alles was jetzt noch kommt klingt mir nach den Anfängen von „Nein“ - „Doch“ - „Nein“ - „Doch“ - „NEIN“ - „DOCH!“ - „Aua!!!!“...

      Rolf

      --
      sumpsi - posui - clusi
      1. @Rolf B

        Meinungen hast Du gehört

        leider war da kein Beispiel dabei was den Vorteil von Exceptionklassen begründen würde oder gezeigt hätte.

        MfG

        1. Hallo pl,

          eigentlich waren da genug Beispiele. Für individuelle Attribute spezieller Exceptions, für Funktionalität der Laufzeitplattform, die an der Systemklasse "Exception" hängt (z.B. Beschaffen des Stacktrace), für filternde Catches...

          Diese Runtime-Funktionalität scheint in Perl so nicht gegeben, in JavaScript übrigens auch nicht. Mit JavaScript kann ich beliebige Werte werfen, in Perl kann ich beliebige Werte als Todesursache angeben. In PHP, Java oder C# nicht, da muss das geworfene Dings werfbar sein (implementiert eine Art von Throwable, oder ist Subklasse von System.Exception) oder das Ding fällt mir mein Werfen auf die Füße. D.h. viele Laufzeitumgebungen zwingen dich einfach zum Gebrauch eines vordefinierten oder selbst abgeleiteten Exception-Objekts.

          Perl und JavaScript tun das nicht, und bringen demzufolge auch ein paar Features nicht mit, die eine zwangsobjektorientierte Exceptionsteuerung hat. Mozilla hat zwar versucht, im Firefox bedingte Catches einzubauen (catch (e if e instanceOf FooException)), aber das ist nicht Standard geworden. Das stack-Property ist zwar immerhin breit implementiert, aber nicht mit einheitlicher Struktur.

          Insofern: Mangels Standardisierung und Unterstützung durch die Laufzeitumgebung ist in Perl und JavaScript der Nutzen von Exception-Objekten weniger groß als in anderen Sprachen. In JS gibt's immerhin die Error-Klassen, aber die Standardproperties sind mager.

          Nebenbei:

          Perl's Error.pm ist übrigens deprecatet.

          Zumindest nicht mehr vom Autor empfohlen. Nimmst Du eben seine Empfehlung try::tiny.

          Rolf

          --
          sumpsi - posui - clusi
          1. @Rolf B

            Anstatt Perl-bashing zu betreiben solltest Du Dich besser informieren. Guck Dir mal die Module Diagnostics, Exception::Class, Try::Tiny, DB und Carp an respective CGI::Carp. Angesichts dessen von mangelhafter Unterstützung zu reden ist einfach nur peinlich!

            .

            1. Anstatt Perl-bashing zu betreiben solltest Du Dich besser informieren.

              LOL

              Guck Dir mal die Module ... Try::Tiny...

              Genau das hat Rolf B in seinem Post sogar erwähnt. Vielleicht solltest Du Posts lesen, bevor Du auf sie antwortest.

              Angesichts dessen von mangelhafter Unterstützung zu reden ist einfach nur peinlich!

              LOL

            2. Hallo pl,

              damit sind wir dann dem Aua etwas näher gekommen.

              Nicht jede Beschreibung eines Unterschieds ist Bashing. Das Wort "mangelhaft" ist von Dir. Ich zünde jetzt mal eine Sperrabstimmung am Root-Posting dieses Threads.

              Rolf

              --
              sumpsi - posui - clusi
              1. Hallo Rolf,

                meine Stimme hast du: Es geht in Gezänk über und wir kommen inhaltlich auch nicht mehr weiter.

                Danke,
                Robert

              2. Hallo Rolf B,

                … Sperrabstimmung …

                ist hier wirklich alles Müll? Reicht es nicht, nur einfach zu zu machen?

                Gruß
                Jürgen

                1. Aloha ;)

                  ist hier wirklich alles Müll? Reicht es nicht, nur einfach zu zu machen?

                  Die Sperrabstimmung schließt nur und löscht nicht. Insofern ist da alles in Ordnung.

                  Grüße,

                  RIDER

                  --
                  Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                  # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
        2. Moin,

          leider war da kein Beispiel dabei was den Vorteil von Exceptionklassen begründen würde oder gezeigt hätte.

          wie man an deinen fundierten Gegenargumenten zu den Beispielen ja nachlesen kann … wenn es denn diese Gegenargumente (verschriftlicht) gäbe. Hier Herumhaten und dann Antworten weder zur Kenntnis nehmen noch zu lesen ist wirklich allerunterste Schublade.

          Grüße
          Robert