Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden)



  • @hustbaer sagte in Welche Sprachfeatures sollte man vermeiden?:

    @It0101 sagte in Welche Sprachfeatures sollte man vermeiden?:

    exit_calc

    Es geht weniger darum ob und wie viel die exit_calc Variante langsamer ist. Es geht darum dass sie viel schwerer zu lesen ist. In echt sind das ja keine leeren Schleifen. Da ist noch Code, meist in jeder Schleife (also z.B. Code der nach der inneren Schleife noch in der äusseren Schleife ausgeführt wird). Und das wird dann ganz schnell ganz unübersichtlich.

    Die goto Variante ist dagegen quasi immer trivial zu lesen.

    Das mag sein, aber das war nicht das Argument. @john-0 hat explizit mit der Performance argumentiert.

    Die Goto-Variante ist auch nur dann besser zu lesen, wenn das Sprungziel nicht auf der nächsten Seite ist. Und wenn hier, wie man so hört, die tief-verschachtelten Schleifen hart durchgezogen werden, und im inneren der Schleifen irgendwo auch nur ein bisschen sinnvoller Sourcecode drin ist, dann ist der Spaß mindestens eine Seite groß. Viel Spaß beim Suchen des Sprungziels 😃

    Ich bin aber ehrlich: ich stehe überhaupt nicht auf Verschachtelungstiefen. Im allgemeinen habe ich selten mehr als zwei Ebenen innnerhalb einer Funktion/Methode. Die vier verschachtelten Schleifen triggern mich also hart 😛



  • @It0101 Ah, OK. Die Beiträge bestimmter Leute sehe ich ja nicht 🙂

    Viel Spaß beim Suchen des Sprungziels

    F12/Alt-G/was auch immer der Shortcut für "go to definition" ist. Bzw. ohne Tool-Support einfach ein "find" mit dem Namen des Labels machen.
    Das Suchen des Sprungziels ist ein triviales Problem.
    Den Code Zeile für Zeile durchzugehen um zu sehen was noch alles ausgeführt wird nachdem die Hilfsvariable gesetzt wurde ist dagegen nicht trivial.
    Ich hab da Fälle gesehen wo alle verschachtelten Schleifen auf eine Bildschirmseite gepasst haben, und es einem trotzdem das Hirn zerbröselt hat beim Versuch zu verstehen wie der Abbruch da genau funktioniert. Super "lustig" ist dann auch das Fehlersuchen in solchem Code.



  • @manni66 sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    Sehe ich anders. C++ best practices und Guidelines raten von goto ab.

    C++ Core Guidelines ES.76: Avoid goto

    Exception

    Breaking out of a nested loop. In that case, always jump forwards.

    Dann nehmen wir mal das Beispiel aus den Guidelines:

    void foo()
    {
       for (int i = 0; i < imax; ++i)
          for (int j = 0; j < jmax; ++j) {
             if (a[i][j] > elem_max) goto finished;
               // ...
          }
       finished:
       // ...
    }
    

    geht auch als

    void bar()
    {
       [&] {
          for (int i = 0; i < imax; ++i)
             for (int j = 0; j < jmax; ++j) {
                if (a[i][j] > elem_max) return;
                // ...
             }
       } ();
       //...
    }
    


  • @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    geht auch als

    Es mag sein, dass das Beispiel dort ungeschickt gewählt ist. Es ging mir aber auch nur darum, dass zumindest die Core Guidelines explizit eine Ausnahem vom kein goto machen.



  • @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    geht auch als [Version mit Lambda]

    findest du das lesbarer?

    Lambdas schön und gut, aber man siehst bei dem if das return und denkt sich, da wird aus bar rausgesprungen. Dann fällt irgendwann das unscheinbare [&] auf. Für mich ist so eine anonymes, direkt ausgeführtes Lambda, das dann noch mehr als 1-2 Zeilen Code hat, schlecht lesbar.



  • @wob
    Ne, finde ich nicht lesbarer. Man kann das auch benennen und explizit aufrufen. Oder als Funktionsaufruf ausgliedern, mir ging´s da nur um´s goto. Aus meiner Sicht ist goto immer noch überflüssig.



  • @DocShoe sagte in [Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden)](/forum

    geht auch als

    void bar()
    {
       [&] {
          for (int i = 0; i < imax; ++i)
             for (int j = 0; j < jmax; ++j) {
                if (a[i][j] > elem_max) return;
                // ...
             }
       } ();
       //...
    }
    

    Das sehe ich als extrem schlechtes Design an, weil die Syntax von C++ sehr gut kennen muss, um überhaupt zu verstehen, was da passiert. Lambdas sind in dieser Hinsicht eine deutliche Verschlechterung der Lesbarkeit von Programmcode. Lambdas führen zu recht hässlichem Code, der zar kompakt ist und für den C++-Profi geht zu verstehen ist, aber für alle anderen nicht.

    goto ist an dieser Stelle ohne hässlichen Seiteneffekte und man sieht sofort was passiert. Das ist deutlich besseres Design.



  • @*john-0
    @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    Ne, finde ich nicht lesbarer. Man kann das auch benennen und explizit aufrufen. Oder als Funktionsaufruf ausgliedern, mir ging´s da nur um´s goto. Aus meiner Sicht ist goto immer noch überflüssig.


  • Mod

    Dieser Beitrag wurde gelöscht!

  • Mod

    @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    @*john-0
    @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    Ne, finde ich nicht lesbarer. Man kann das auch benennen und explizit aufrufen. Oder als Funktionsaufruf ausgliedern, mir ging´s da nur um´s goto. Aus meiner Sicht ist goto immer noch überflüssig.

    Aber den variablen Sprung kannst du prinzipiell immer noch nicht damit emulieren, egal wie du dich verrenkst. Und voraussichtlich wird keine der goto-Vermeidungsstrategien hier zu einem besser lesbaren Code führen. Es gibt schon einen Grund, wieso dieses Konstrukt immer als das Beispiel für das gute goto herangezogen wird. Ist auch so ungefähr das einzige Beispiel für ein gutes goto, aber es ist ein gutes Beispiel.

    Hier, zum Austoben

    for (i…)
    {
      for (j…) 
      {
        for(k…)
        {
          rechnung(i, j, k);
          if (i ist sinnlos) goto i_continue;
          if (j ist sinnlos) goto j_continue;
        }
        j_continue:
      }
      i_continue:
    }
    


  • for( i.... )
    {
       for( j... )
       {
          for( k... )
          {
             rechnung( i, j, k );
             if( i ist sinnlos || j ist sinnlos ) break;
          }
          if( i ist sinnlos ) break;
       }
     }
    

    Aber ich sehe deinen Punkt. Bei drei Verschachtelungstiefen geht das noch, aber bei mehreren werden die if-Abfragen unübersichtlich und die Abbruchbedingungen verteilen sich auf mehrere Zeilen Quelltext.



  • @DocShoe

    Warum nicht so, sofern es algorithmisch möglich ist?

    int MeineRechnung(i, j, k)
    {
      for(k…)
      {
        rechnung(i, j, k);
        if (i ist sinnlos) 
          return i_continue;
        if (j ist sinnlos)
          return;
      }
    }
    
    for (i…)
    {
      for (j…) 
      { 
    	if (MeineRechnung(i, j, k) == i_continue)
    		break;
      }
      i_continue:
    }
    

    Meine is, js uns ks werden schnell groß. Von daher mag ich kleine Funktionen, welche ich seperat testen kann, bevor ich eine O(n^3) Operation starte.


  • Mod

    @Quiche-Lorraine : Das ist ja genau der Lösungsansatz, den ich und andere kritisiert haben.

    • Du hast die Logik des Algorithmus, die vorher auf einen Blick direkt erfassbar war, auf mehrere Stellen im Quellcode verteilt.
    • Man muss genau das Verhalten der Unterfunktion kennen, um den Code der aufrufenden Ebene verstehen zu können. Was ein Zeichen für eine schlecht definierte Funktion ist.
    • Die Funktion ist fest daran gebunden, dass der aufrufende Kontext genau so aussieht wie hier. Ein weiteres Zeichen für eine schlecht definierte Funktion.
    • Du hast auch noch eine Conditionvariable und deren Abfrage eingebaut, wo doch das eigentliche Ziel war, so etwas zu vermeiden

    Der Code ist in jeder Hinsicht schlechter gemacht als das Original. Das nur um dogmatisch das goto zu vermeiden, obwohl das vollständige Dogma doch sogar explizit eine Ausnahme macht für diesen Fall.

    @DocShoe : Du hast die Extrafunktionen zwar nicht, aber halt auch die Extracondition, die jetzt bei jedem Durchlauf gecheckt werden muss. Was vorher nicht da war. Wenn Laufzeit geopfert wird für Dogmatismus, dann ist das Dogma falsch (oder hier: Unvollständig, da es eigentlich hier die Ausnahme zulässt)



  • @DocShoe sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    Wenn ich in verschiedenen Schleifenrümpfen gotos habe, die an Sprungmarken springen, die ich aufgrund der Anzahl der Zeilen nicht mal sehen kann, weil ich dazu scrollen muss?

    Dann kannst du zumindest auch innere Schleifen-Blocks in andere Funktionen verlagern.



  • @SeppJ sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    @DocShoe : Du hast die Extrafunktionen zwar nicht, aber halt auch die Extracondition, die jetzt bei jedem Durchlauf gecheckt werden muss. Was vorher nicht da war. Wenn Laufzeit geopfert wird für Dogmatismus, dann ist das Dogma falsch (oder hier: Unvollständig, da es eigentlich hier die Ausnahme zulässt)

    Bei solchen Sachen bin ich vorsichtig geworden und hab ungeheuer Respekt vor dem Optimierungsvermögen aktueller Compiler bekommen. Nur weil da eine zusätzliche Überprüfung gemacht wird heißt das nicht, dass die auch so im binary steht. In Godbolt´s Compilerexplorer hab ich mal ein (völlig praxisfernes) Miniprogramm mit drei verschachtelten Schleifen anzeigen lassen, dabei hat der clang 9 mit -O2 ein komplettes loop-unrolling gemacht und ist nur über die tatsächlich benötigten Laufvariablenwerte gelaufen. Beide Varianten erzeugten etwa gleich langen Assembleroutput (wobei die goto-Variante etwas länger war. Wie teuer (in CPU Zyklen) beide Varianten waren kann ich allerdings nicht sagen). Ab clang 10 stand das Ergebnis als Konstante im Assembleroutput, da gab´s überhaupt keine Schleifen mehr.
    Wie sich das im Real-World Fall verhält weiß immer noch niemand.



  • Ich finde, hier wird einfach zu vehement gegen ein goto argumentiert. Natürlich ist das zu 99,99% schlecht und wird auch überall so verbreitet. Aber wenn man doch mal einen Fall hat, wo das passt, dann ist es auch kein Weltuntergang, das zu benutzen. Ich sehe keinen Grund, das unbedingt um jeden Preis vermeiden zu wollen.
    Wobei ich auch dazu sagen muss, dass ich selber noch kein einziges mal goto verwendet habe.



  • @Mechanics sagte in Goto considered harmful!? (Fork aus: Welche Sprachfeatures sollte man vermeiden):

    Ich finde, hier wird einfach zu vehement gegen ein goto argumentiert. Natürlich ist das zu 99,99% schlecht und wird auch überall so verbreitet. Aber wenn man doch mal einen Fall hat, wo das passt, dann ist es auch kein Weltuntergang, das zu benutzen. Ich sehe keinen Grund, das unbedingt um jeden Preis vermeiden zu wollen.
    Wobei ich auch dazu sagen muss, dass ich selber noch kein einziges mal goto verwendet habe.

    Mit goto ist es wie mit der AFD. Auch was die fordern ist nicht zu 100% Unsinn, aber eben zu 99%. Wenn man dann aber das 1% positiv hervorhebt, dann kommen irgendwelche Deppen daher und sagen: "ja der da hat gesagt, die AFD ist total gut", einfach weil sie es nicht besser wissen und mangels neuronaler Leistungsfähigkeit komplexere Dinge auch gar nicht erfassen können.


  • Mod

    Ich glaube es ist gut mit den implizierten Beleidigungen. Das muss nicht sein, sonst mache ich den Thread zu. Thema scheint ja auch durch zu sein.



  • Mir ging´s nur um konkrete Beispiele, wo goto sinnvoll eingesetzt werden kann. Mir reichten da Pauschalaussagen einfach nicht aus, und es hat ja auch einige Zeit gedauert, bevor da was Brauchbares kam. Ja, man kann seinen Quelltext immer ohne goto umformulieren, nur ist das goto in einem Fall doch sinnvoll einzusetzen, weil alles andere zu umständlich werden kann. Lesson learned, ich bin hier fertig.


Anmelden zum Antworten