pl: Frage zum Wiki-Artikel „Fehlerbehandlung“

problematische Seite

hi 😉

function teste_x (Zaehler) {
      try {
        if (x == 2) {
          throw "richtig";
        } else if (x == 3) {
          throw "falsch";
        }
      } catch (e) {
        if (e == "richtig") {
          zeigeErgebnis(Zaehler, e);
          return;
        } else if (e == "falsch") {
          zeigeErgebnis(Zaehler, e);
          return;
        }
      } finally {
        Zaehler++;
      }

also throw "richtig" erscheint mir als ein bischen zu sehr paradox: Eine Exception zu werfen um dann anhand des Fehlertextes festzustellen, daß es keinen Fehler gab 😉

Ne, na!?

  1. problematische Seite

    Brrr. Das eigentliche Problem hast Du nicht einmal berührt. Das Beispiel ist auf derart vielen Ebenen WTF, ich weiß gar nicht wo ich anfangen soll.

    • Um eine Variable mit try/catch auf Existenz zu prüfen, muss man im strict-Mode arbeiten
    • Im strict-Mode funktioniert das Beispiel aber nicht, weil beide Versuche einer "Erfolg" Abfrage einen ReferenceError werfen.
    • Der "gute" Ausgang erfolgt per throw. Exceptions sollen aber den "bösen" Ausgang behandeln.
    • Das Beispiel schmeißt mit Globals um sich und initialisiert die Variable Zähler nicht (was im strict mode ebenfalls einen ReferenceError wirft)
    • Das Beispiel schmeißt etwas, das kein Error-Objekt ist, bzw. nicht die Mindestanforderung erfüllt, die Eigenschaften "name" und "message" mitzubringen. Das ist technisch möglich, gehört aber in diesen polnisch klingenden Kurort (Bad Practice)

    Wenn schon, dann eher so:

    "use strict"
    
    setTimeout("x=3", 200);
    teste_x(0);
    
    function teste_x (z) {
       try {
          zeigeErgebnis(z, (x == 2) ? "erwartet" : "unerwartet");
       } catch (e) {
          if (e.constructor === ReferenceError)
             setTimeout(function() { teste_x(z+1); }, 30);
       }
    }
    
    function zeigeErgebnis (Zaehler, Ergebnis) {
       alert("Nach " + (Zaehler) + " Durchläufen existierte x.\nDie Zahl x ist " + Ergebnis + ".")
    }
    

    Aber auch da steckt noch ein WTF Würmchen drin: Der setTimeout, der x=3 setzt, ist ein versteckter eval(), der den Strict-Mode abschaltet und damit das implizite Erzeugen von x ermöglicht. Schreibt man dort function() { x=3; } hin, crasht dieser Timeouthandler. Alles Dinge, die man im Artikel erwähnen müsste und womit man vom Thema ablenkt.

    Wenn mir ein besseres Beispiel einfällt, werde ich da mal aktiv werden (sofern sonst keiner schneller ist).

    Rolf

    --
    sumpsi - posui - clusi
    1. problematische Seite

      Hallo Rolf B,

      Wenn mir ein besseres Beispiel einfällt, werde ich da mal aktiv werden (sofern sonst keiner schneller ist).

      👍

      Bis demnächst
      Matthias

      --
      Rosen sind rot.
    2. problematische Seite

      Hallo,

      als Anregung hier mal eine Anwendung von try-catch aus einem meiner Scripte:

      var init = function() {
        try {
          workerscript = window.URL.createObjectURL(new Blob([document.getElementById("mandel_worker").textContent],{type:'application/javascript'}));
          mandelbrot_worker[0] = new Worker(workerscript); 
          mandelbrot_worker[1] = new Worker(workerscript); 
      		var tmp = new ArrayBuffer(4);
        }
        catch(e) {
          // Hier die Fehlerbehandlung
          return;
      	}}	
      

      Hier hätte ich per feature-Request mehrere Objekte abfragen müssen. So verwende ich sie einfach und breche ab, wenn eines nicht so funktioniert. In der Testphase sollte man das try-catch natürlich weglassen, da man so ja keine Fehlermeldung bekommt.

      Gruß
      Jürgen

      1. problematische Seite

        Tach!

        In der Testphase sollte man das try-catch natürlich weglassen, da man so ja keine Fehlermeldung bekommt.

        Man kann diese im catch-Block mit console.log() ausgeben. Vielleicht auch konditional, so dass im Produktivbetrieb der Aufruf unterlassen wird.

        dedlfix.

    3. problematische Seite

      Tach!

      Wenn mir ein besseres Beispiel einfällt, werde ich da mal aktiv werden (sofern sonst keiner schneller ist).

      try-catch in Javascript ist etwas schwierig. Üblicherweise nimmt man das nicht, um eigene Programmierfehler abzufangen, sondern mehr wenn externe Services fehlschlagen. Diese fragt man aber asynchron ab, und dafür geht try-catch nicht wirklich. Wenn der Callback im try-Teil liegt, zieht try-catch nicht, weil für den Callback zwar Closures aufgehoben werden, aber nicht der gesamte Kontext. Das Callback läuft also nicht in dem Block, obwohl es darin notiert ist.

      Anderer Versuch: Eine Funktion (vielleicht aus einer Bibliothek) nimmt Parameter entgegen und prüft den Typ. Wenn er unpassend ist, wirft sie eine Exception. Allerdings ist es meist unsinnig, diese Exception im aufrufenden Teil fangen zu wollen, denn eigentlich hat man einen logischen Fehler im Programm, der es zulässt, dass diese Funktion mit falschen Parameter aufgerufen wird. Exceptions sind kein Ersatz für Prüfungen. Division durch Null ist ein ebensolches Thema. Besser vorher die Operanden prüfen statt das Programm in eine Exception reinlaufen zu lassen.

      dedlfix.

      1. problematische Seite

        Wenn mir ein besseres Beispiel einfällt, werde ich da mal aktiv werden (sofern sonst keiner schneller ist).

        try-catch in Javascript ist etwas schwierig...

        Für mich ist "JSON.parse" der Klassiker schlechthin für try-catch in JavaScript.

        1. problematische Seite

          Tach!

          Wenn mir ein besseres Beispiel einfällt, werde ich da mal aktiv werden (sofern sonst keiner schneller ist).

          try-catch in Javascript ist etwas schwierig...

          Für mich ist "JSON.parse" der Klassiker schlechthin für try-catch in JavaScript.

          Ja, das passt. Das arbeitet synchron und mit meistens externen Daten, die man schlecht vorab prüfen kann. Einen Parseversuch zu starten, der mit Exception fehlschlagen kann, halte ich für ein effektives und effizientes Verfahren.

          Auch Zugriffe ins Dateisystem schlagen in eine ähnliche Kerbe, aber scheint mir für das Beispiel ungeeignet, weil nicht Mainstream genug.

          dedlfix.

          1. problematische Seite

            Auch Zugriffe ins Dateisystem schlagen in eine ähnliche Kerbe, aber scheint mir für das Beispiel ungeeignet, weil nicht Mainstream genug.

            +1

            Wobei ich das aktuelle Beispiel auch für mindestens fragwürdig halte. Und ja, ich bin schlicht zu faul, es zu ändern. Deshalb halte ich auch die Fresse ;-)

            1. problematische Seite

              @@Mitleser

              Wobei ich das aktuelle Beispiel auch für mindestens fragwürdig halte. Und ja, ich bin schlicht zu faul, es zu ändern. Deshalb halte ich auch die Fresse ;-)

              Das h<I>lft d<I>r jetzt auch n<I>cht mehr. ;-)

              LLAP 🖖

              --
              “When UX doesn’t consider all users, shouldn’t it be known as ‘Some User Experience’ or... SUX? #a11y” —Billy Gregory
            2. problematische Seite

              Tach!

              Wobei ich das aktuelle Beispiel auch für mindestens fragwürdig halte. Und ja, ich bin schlicht zu faul, es zu ändern. Deshalb halte ich auch die Fresse ;-)

              Nicht schön, aber sowas in der Art sollte es sein:

              var json = "Ich bin kein JSON, ich bin kaputt."; // kommt eigentlich aus irgendeiner Datenabfrage
              
              try {
              	var daten = JSON.parse(json);
              	
              	// weitere Verarbeitung wenn das Parsen erfolgreich war
              	console.log(daten);
              
              } catch (e) {
                // Reaktion auf den Fehlerfall
              	console.log(e);
              }
              

              Das, was im Gut- und was im Fehlerfall passieren soll, ist so anwendungsfall-individuell, dass ich hier keine gescheite beispielhafte Vorgehensweise angeben kann. Aber im Zweifelsfall landet bei Code-Kopierern jeglicher Beispielcode in der fertigen Anwendung, egal wie sinnvoll er im Beispiel war, ohne dass er in dem Fall beim Verwender sinnvoll wäre.

              dedlfix.

              1. problematische Seite

                Nicht schön, aber sowas in der Art sollte es sein:

                var json = "Ich bin kein JSON, ich bin kaputt."; // kommt eigentlich aus irgendeiner Datenabfrage
                
                try {
                	var daten = JSON.parse(json);
                	
                	// weitere Verarbeitung wenn das Parsen erfolgreich war
                	console.log(daten);
                
                } catch (e) {
                  // Reaktion auf den Fehlerfall
                	console.log(e);
                }
                

                Viel, viel besser als das aktuelle Beispiel!

      2. problematische Seite

        Exceptions sind kein Ersatz für Prüfungen.

        Sind sie auch nicht. Aber sie vereinfachen den Programmablauf, z.B. so daß man bei einer fehlerhaften Benutzereingabe per Exception das Programm beendet wenn es keinen Sinn macht, es mit einer fehlerhaften Benutzereingabe weiterlaufen zu lassen.

        Natürlich werden auch solche Exceptions aufgefangen, erstens damit der Benutzer eine Fehlermeldung kriegen und zweitens das Programm sauber beendet werden kann. Fängt man Exceptions nicht auf, meldet sich das Programm/Script mit einem Fehlercode != 0 an das Betriebssystem bzw. an die VM zurück, auf deutsch gesagt, es stirb.

        Beispiel einer Fehlerbehandlung per Exception:

        my $sca = Scaliger->new( date => $self->param('date') )
          || return $self->errmsg("$@");
        

        Wobei da der Wurf der Exception bereits im Konstruktor der Klasse Scaliger erfolgt und an dieser Stelle aufgefangen wird. Anstelle der $sca~Instanz gibt der Konstruktor ein undef zurück und woran es gescheitert ist, steht in einer globalen Variable $@ z.B.: "Das eingegebene Datum ist nicht gültig!"

        Nach diesem Prinzip, gestützt auf das Carp Module, setzen viele CPAN Autoren ihre Module auf, weil sich das doch tatsächlich so bewährt hat. Wobei Carp::croak() einen Backtrace liefert der genau auf die Zeile zeigt, wo's passiert ist, was jedoch hauptsächlich für den Entwickler gedacht ist:

        my $person = Person->new() 
         || die $@;
        
        # und in $@ steht z.B.: -name erforderlich at .... line 37.
        

        Schönen Sonntag.

    4. problematische Seite

      Brrr. Das eigentliche Problem hast Du nicht einmal berührt.

      Doch genau das. Das Beispiel geht am Prinzip try/catch nämlich völlig vorbei. Wobei ein throw("Fehlermeldung"); vom Prinzip her ja absolut legitim ist, im catch()Block jedoch den Fehlertext zu parsen um daran festzumachen ob es einen Fehler gab oder nicht ist totaler Unfug. Weil:

      Im catch()Block angekommen, die Exception ja erstens schon gefallen ist und zweitens ja auch feststeht welches Bauteil seinen Dienst quittiert hat.

      Und das heißt: Ende des Programms. Genau deswegen wirft man ja eine Exception, weil eine Fortführung des Programms nicht mehr sinnvoll ist und u.U. weitere Schäden anrichten würde.

      throw "richtig"; ist der Blödsinn.

      MfG

    5. problematische Seite

      Hallo,

      ich habe jetzt mal im ersten Schritt den ersten Teil des Artikels umgeschrieben. "onerror" ist heute ganz falsch, globale Variablen im Errorhandling auch, weniger falsch ist addEventListener("error", f), aber man darf das nicht beschreiben ohne dabei zu sagen, dass DAS nicht der gute Weg für lokales Errorhandling ist.

      Die Behauptung im Artikel, dass man die Programmausführung fortsetzen könnte, musste ich auch streichen. Kommt man im error-Event an, ist der Execution Stack abgeräumt. Bestenfalls wartet noch die Mikro-Queue auf ihre Ausführung.

      Rolf

      --
      sumpsi - posui - clusi
      1. problematische Seite

        Moin,

        der Käse ist ja immer noch drin:

        1. test_x
        2. oh, eine Exception 2a. wenn im Fehlertext 'richtig' steht machen wir dies.. 2b. wenn 'falsch' steht machen wir was anderes

        Obwohl eine Exception in jedem Fall geworfen wurde:

        try {
                if (x == 2) {
                  throw "richtig";
                } 
                else if (x == 3) {
                  throw "falsch";
                }
        }
        

        So geht man doch nicht mit Exceptions um, das ist ja schon vom Ansatz her falsch!

        Die Behauptung im Artikel, dass man die Programmausführung fortsetzen könnte, musste ich auch streichen.

        try/catch erlaubt ja die Fortsetzung. Nur macht sie halt i.d.R. keinen Sinn.

        Schönen Sonntag 😉

        1. problematische Seite

          Hallo pl,

          Forum:

          ich habe jetzt mal im ersten Schritt den ersten Teil des Artikels umgeschrieben

          Wiki:

          Beispiel muss ich noch überarbeiten, try/catch auch.

          Zu try/catch bin ich erstmal nicht mehr gekommen, als ich den ersten Teil des Texts sah.

          Rolf

          --
          sumpsi - posui - clusi
          1. problematische Seite

            hi Rolf

            Zu try/catch bin ich erstmal nicht mehr gekommen, als ich den ersten Teil des Texts sah.

            Ach so 😉

            Na dann wünsche ich Dir viel Spaß und Erfolg. Wie Du weißt bin ich eher in Perl unterwegs, da gehört der Umgang mit Exceptions zum Handwerk und ist längst in Fleisch und Blut übergegangen wie kuppeln, schalten, gasgeben 😉

            Ich denke jedoch, daß es zu anderen PLs keine grundsätzlichen Unterschiede gibt in Sachen Exceptions. Umgang und Anwendung muss jedoch jeder selber lernen

            MfG

            1. problematische Seite

              Hallo,

              Ich denke jedoch, daß es zu anderen PLs keine grundsätzlichen Unterschiede gibt in Sachen Exceptions. Umgang und Anwendung muss jedoch jeder selber lernen

              wobei man in Javascript wohl in den meisten Fällen ohne try..catch auskommt. Auch mein Beispiel ist ja nur der Bequemlichkeit geschuldet.

              Ich hatte erst einen Fall, bei dem ich try..catch benötigt habe: eine Methode wurde von allen Browsern unterstützt, daher kein Featurerequest, aber auf einem bestimmten Parameterwert reagierten ältere IEs mit einem Syntaxerror. Es ging um die Zuweisung eines Farbwertes im rgba-Format. Inzwischen interessieren diese alten IEs nicht mehr, und ich setze die Farbe über Klassen.

              Gruß
              Jürgen

              1. problematische Seite

                Hallo,

                Ich denke jedoch, daß es zu anderen PLs keine grundsätzlichen Unterschiede gibt in Sachen Exceptions. Umgang und Anwendung muss jedoch jeder selber lernen

                wobei man in Javascript wohl in den meisten Fällen ohne try..catch auskommt.

                Stimmt. Was sicher auch daran liegt daß JS eventgesteuert ist und asynchchron arbeitet. Und dann ist es ja auch einer Frage wie man dem Anwender eine Fehlermeldung möglichst schonend beibringt 😉

                MfG