Ist goto noch evil...



  • Eisflamme schrieb:

    Hier nochmal ganz bewusst der imo schöne Code mit goto:

    for(std::size_t n = 0; n < 100; ++n)
        for(std::size_t m = 0; m < 100; ++m)
            for(std::size_t l = 0; l < 100; ++l)
                if(cube[n][m][l] == "Bananenweizen")
                    goto rausHierRufzeichen;
                else
                    // mach irgendwas
    rausHierRufzeichen:
    

    SCHÖN!

    n = 100;
    ist das weniger schön ?



  • !rr!rr_. schrieb:

    in der OOP braucht man genaugenommen weder goto noch Schleifen, sobald man einen Datentyp "Intervall" hat und einen passenden Iterator.

    Da wär ich aber gespannt, wie du den größten gemeinsamen Teiler von zwei Zahlen effizient ausrechnest. Bitte aber ohne Rekursion, weil das nur ein verstecktes goto ist. Der ggT könnte mit Iteratoren recht schwierig werden. 🙂

    (Technischer Hintergrund der Frage, für Interessierte: http://www.math.uiuc.edu/People/vandendries/gc.pdf )



  • Christoph schrieb:

    Da wär ich aber gespannt, wie du den größten gemeinsamen Teiler von zwei Zahlen effizient ausrechnest. Bitte aber ohne Rekursion, weil das nur ein verstecktes goto ist. Der ggT könnte mit Iteratoren recht schwierig werden. 🙂

    Sind ja bei Euklid nur max 64 Durchläufe für 32-Bitter. Die kann man auch Untereinanderschreiben.

    Wie !rr!rr_. durch Iteratoren Schleifen vermeiden will, weiß ich aber auch nicht. Ich benutze Iteratoren doch oft als Schleifenlaufvariable.



  • volkard schrieb:

    Christoph schrieb:

    Da wär ich aber gespannt, wie du den größten gemeinsamen Teiler von zwei Zahlen effizient ausrechnest. Bitte aber ohne Rekursion, weil das nur ein verstecktes goto ist. Der ggT könnte mit Iteratoren recht schwierig werden. 🙂

    Sind ja bei Euklid nur max 64 Durchläufe für 32-Bitter. Die kann man auch Untereinanderschreiben.

    Guter Punkt. Also ist man mit einem Iterator über ein vorher berechnetes Intervall maximal 64 Mal schlechter als mit Euklid. Das ist gar nicht so schlecht, wie ich zuerst dachte.

    Bei unbeschränktem Input wird es wohl erst richtig fies, wenn man nicht mehr vorher ausrechnen kann wieviele Iterationen Euklid maximal braucht.

    edit: Obwohl es vielleicht auch da wieder anders aussieht, wenn man die log-Funktion zur Verfügung hat. Aber das wär Fließkomma, das will man nicht haben im ggT-Algorithmus, denk ich.



  • edit: Obwohl es vielleicht auch da wieder anders aussieht, wenn man die log-Funktion zur Verfügung hat. Aber das wär Fließkomma, das will man nicht haben im ggT-Algorithmus, denk ich.

    Nehmen wir doch die Länge des Inputs als log.



  • volkard schrieb:

    edit: Obwohl es vielleicht auch da wieder anders aussieht, wenn man die log-Funktion zur Verfügung hat. Aber das wär Fließkomma, das will man nicht haben im ggT-Algorithmus, denk ich.

    Nehmen wir doch die Länge des Inputs als log.

    Die hat man nicht unbedingt verfügbar, weil das ein verstecktes Implementierungsdetail der Sprache sein könnte. Aber OK, ich seh langsam ein, dass mein Beispiel für zu viele Lücken hat, um auf reale Sprachen anwendbar zu sein.

    Es ging mir darum, dass primitiv-rekursive Funktionen nicht in der Lage sind, die Anzahl der benötigten Iterationen des Euklid-Algorithmus im Vorfeld effizient auszurechnen, und zwangsläufig Linear-Zeit brauchen, um den ggT zu ermitteln. Der euklidische Algorithmus braucht nur logarithmische Zeit.

    Die Bemerkung von !rr!rr_. klang für mich danach, als wolle er alles in primitiv-rekursiven Funktionen ausdrücken, d.h. insbesondere alle for-Schleifen iterieren über ein Intervall, das vor der for-Schleife bekannt ist und sich während den Iterationen nicht ändert.



  • ToGoOrNotToGo schrieb:

    ...oder darf man es wieder verwenden?

    Ernst gemeinte Frage.

    Jo, jetzt ist es wieder in Ordnung, die modernen Computer haben genug Rechenpower und dank 64 Bit ist GOTO nun auch kein Problem mehr.



  • Tim06TR schrieb:

    Eisflamme schrieb:

    Hier nochmal ganz bewusst der imo schöne Code mit goto:

    for(std::size_t n = 0; n < 100; ++n)
        for(std::size_t m = 0; m < 100; ++m)
            for(std::size_t l = 0; l < 100; ++l)
                if(cube[n][m][l] == "Bananenweizen")
                    goto rausHierRufzeichen;
                else
                    // mach irgendwas
    rausHierRufzeichen:
    

    SCHÖN!

    n = 100;
    ist das weniger schön ?

    Es ist ca. 100x weniger schön, und macht ausserdem noch was anderes (die inneren Schleifen werden nicht sofort abgebrochen).

    Warum ist es 100x weniger schön? Weil es 100x weniger klar ist. Man muss erstmal 100 Gehirnzellen bemühen um zu verstehen was es tut. Beim goto Code reichen 10.

    Und wenn man es gleich mit return statt goto schreiben würde, dann käme man mit 2-3 Gehirnzellen aus. Also noch besser. Weil klarer.



  • goto ist zurecht verpönt und gewöhnlich überflüssig und vermeidbar!
    Man kann es aber trotzdem benutzen, wenn damit der Code übersichtlicher wird (wird er das?). Dann aber bitte nur an das Ende einer Funktion und zum Nachvollziehen sauber kommentiert. Ein break oder return tut es meist auch, um aus einer komplizierten Schleifenkonstruktion auszusteigen.



  • berniebutt schrieb:

    Dann aber bitte nur an das Ende einer Funktion und zum Nachvollziehen sauber kommentiert.

    Nö. Nicht nur ans Ende.
    Und statt zu kommentieren nimmt man besser sprechende Namen.

    goto label1;//es kann kein Frumpel mehr gestreckt werden
    ...
    label1:;//es kann kein Frumpel mehr gestreckt werden
    ...
    
    goto es_kann_kein_Frumpel_mehr_gestreckt_werden;
    ...
    es_kann_kein_Frumpel_mehr_gestreckt_werden:;
    ...
    


  • goto ist außerdem nützlich, um die bösen if-Blöcke und for-Schleifen aus dem Quellcode zu verbannen: http://www.c-plusplus.net/forum/275649-full
    Das geht leider nur mit dem GCC Compiler 😞
    if und for, bäh...
    🙂



  • volkard schrieb:

    Nö. Nicht nur ans Ende.
    Und statt zu kommentieren nimmt man besser sprechende Namen.

    Sprechende Namen? 😕 ok!

    ...
    hell:
    ...
    goto nirwana;
    ...
    nirwana:
    ... goto hell;
    ...
    

    Solche Codes aus ersten BASIC-Zeiten habe ich immer sehr geliebt.
    fantastico! 😃



  • Schleifen sind sehr wohl durch Intervall und Iterator ersetzbar. Alle in der Praxis auftretenden Schleifen werden höchstens 1e1000-mal durchlaufen, also reichen endliche Intervalle vollkommen aus.

    Bleibt noch die Endlosschleife - die tritt in der Praxis nicht auf, weil kein Programm unendlich lange läuft.



  • Und wie willst du eine Schleife ersetzen, bei der du vorher nicht weißt, wie lange sie überhaupt laufen soll? Ich kenne genug Programme, die bestimmte Aktionen so lange wiederholen, bis von außen ein "jetzt ist Schluß" Signal gesendet wird (hab auch selber schon welche geschrieben).

    (PS: Und wie ist ein Intervall intern realisiert? Vermutlich auch wieder über eine Schleife, die den Iterator weiterschiebt bis er das Ende erreicht hat)



  • berniebutt schrieb:

    ...
    hell:
    ...
    goto nirwana;
    ...
    nirwana:
    ... goto hell;
    ...
    

    Na, das ist ja trivial... es gibt z.B. so was:

    /* Hier macht jemand viele Sachen und bei Fehler springt er ans Ende der Funktion */
    if (err)
        goto label_a;
    ...
    if (err)
        goto label_b;
    ...
    if (err)
        goto label_c;
    ...
    if (err)
        goto label_d;
    ...
    if (err)
        goto label_e;
    ...
    /* keine Fehler, einfach return 0 */
        return 0;
    /* und das ist eine Art "Destruktor" am Ende der Funktion: */
    label_e:
        ...
    label_d:
        ...
    label_b:   /* Warum label_b vor label_c... */
        ...
    label_c:
        ...
    label_a:
        ...
        return err;
    

    warum kommt label_b vor label_c... 😕 🙂



  • !rr!rr_. schrieb:

    Schleifen sind sehr wohl durch Intervall und Iterator ersetzbar. Alle in der Praxis auftretenden Schleifen werden höchstens 1e1000-mal durchlaufen, also reichen endliche Intervalle vollkommen aus.

    Bleibt noch die Endlosschleife - die tritt in der Praxis nicht auf, weil kein Programm unendlich lange läuft.

    Die Ackermann-Funktion ist nicht LOOP-berechenbar.

    Edit: Ein bisschen ausführlicher:
    IIRC in den späten Zwanzigern hat man geglaubt, dass man keine Endlosschleife brauchen würde, um Turing-vollständig zu werden. Das trifft jedoch nicht zu. Ackermann hat eine Funktion konstruiert, die durch Turingmaschinen berechenbar ist, aber so schnell wächst, dass sie nicht mit Schleifen berechnet werden kann, bei denen vorher die Anzahl der Durchläufe feststeht.



  • hab' ich gesagt, daß die Anzahl Durchläufe vorher feststehen muß? 😕

    Schleifen, die bei Eintreten einer Bedingung abbrechen, lassen sich auch durch Intervall und Iterator ersetzen:

    [ 1 to: 1e1000 do: [ :i | 
    	1/(4-i). Transcript show: i ] ] 
    	on: Error do: [ 
    		Transcript show: 'oops ...' ].
    "123oops ..."
    


  • !rr!rr_. schrieb:

    hab' ich gesagt, daß die Anzahl Durchläufe vorher feststehen muß? 😕

    Lies doch bitte die Postings von Michael E. und bei Dir unbekannten Begriffen schau sie wenigstens oberflächlich im Netz nach.



  • wozu? hast du mein Posting nicht verstanden?



  • !rr!rr_. schrieb:

    wozu? hast du mein Posting nicht verstanden?

    Gegenfrage: Hast du überhaupt die grundlegenden Konzepte der Berechenbarkeit verstanden? Du kannst mit endlichen Schleifen nicht alles ausrechnen, egal wie groß die Anzahl der Durchläufe auch gesetzt wird.


Anmelden zum Antworten