Martin G.: Pro/Contra Break in Schleifen

Hallo allerseits,

da ich diese Diskussion in letzter Zeit mehrfach hatte, würde mich mal eure Meinung - soz. aus der harten Praxis - interessieren: was haltet ihr von break-Anweisungen innerhalb von Schleifen?

Was spricht dagegen? Was dafür?

Konkret geht es in unserem Fall um PHP!

Liebe Grüße,
Martin

  1. da ich diese Diskussion in letzter Zeit mehrfach hatte, würde mich mal eure Meinung - soz. aus der harten Praxis - interessieren: was haltet ihr von break-Anweisungen innerhalb von Schleifen?

    Was spricht dagegen?

    Wahrscheinlich Du.

    Was dafür?

    Ich.

    Konkret geht es in unserem Fall um PHP!

    Konkret es geht um Scriptsprachen allgemein.
    Du hast noch nicht einmal spezifiziert,
    um welche Art von Schleife es sich handelt.

    mfg Beat

    --
    ><o(((°>           ><o(((°>
       <°)))o><                     ><o(((°>o
    Der Valigator leibt diese Fische
    1. Hi!

      » da ich diese Diskussion in letzter Zeit mehrfach hatte, würde mich mal eure Meinung - soz. aus der harten Praxis - interessieren: was haltet ihr von break-Anweisungen innerhalb von Schleifen?
      »
      » Was spricht dagegen?

      Wahrscheinlich Du.

      Glaskugel geputzt, was?

      » Was dafür?
      Ich.

        
      <ask mode="advocatus diaboli">Warum?</ask>  
      
      

      » Konkret geht es in unserem Fall um PHP!
      Konkret es geht um Scriptsprachen allgemein.

      Nein, der OP hat doch von PHP geschrieben.

      Du hast noch nicht einmal spezifiziert,
      um welche Art von Schleife es sich handelt.

      Stimmt!

      off:PP

      --
      "You know that place between sleep and awake, the place where you can still remember dreaming?" (Tinkerbell)
      1. » Was dafür?
        Ich.

        <ask mode="advocatus diaboli">Warum?</ask>

        
        >   
        > > » Konkret geht es in unserem Fall um PHP!  
        > > Konkret es geht um Scriptsprachen allgemein.  
        >   
        > Nein, der OP hat doch von PHP geschrieben.  
          
        Tja und ich hab mir das Recht genommen, das auf last in Perl anzuwenden.  
        while() ohne definiertes last ist ein Spiel mit der CPU.  
          
        Auch kann ich bei last positive Bedingungen beschreiben.  
        Das Beschreibung negativer Bedingungen um weiterzufahren, erscheint mir wenig günstig.  
          
        mfg Beat
        
        -- 
        
        ><o(((°>           ><o(((°>  
        
           <°)))o><                     ><o(((°>o  
        Der Valigator leibt diese Fische
        
    2. Hallo Beat,

      Du hast noch nicht einmal spezifiziert,
      um welche Art von Schleife es sich handelt.

      Lasst uns mal annehmen, es handelt sich um eine foreach-Schleife zum Durchlaufen eines Arrays.

      Die Break-Version sähe so aus:

      foreach($myArray as $currElement)  
      {  
         if ($whatever)  
         {  
            break;  
         }  
         echo $currElement;  
         // mach noch mehr...  
      }
      

      Die Version ohne Break sähe bspw. so aus:

        
      foreach($myArray as $currElement)  
      {  
         if (!$whatever)  
         {  
            echo $currElement;  
            // mach noch mehr...  
         }  
      }
      

      (Natürlich vorrausgesetzt, dass die Bedingung $whatever nur einmal ihren Zustand ändern kann. Ansonsten wird's ein kleines bisschen aufwändiger.

      Switch (wie von Peter Pan eingeworfen) ist keine Schleife, betrifft also auch nicht die eigentliche Frage.

      Martin

      1. Hallo Martin,

        Die Break-Version sähe so aus:

        foreach($myArray as $currElement)

        {
           if ($whatever)
           {
              break;
           }
           echo $currElement;
           // mach noch mehr...
        }

          
        
        > ~~~php
          
        
        > foreach($myArray as $currElement)  
        > {  
        >    if (!$whatever)  
        >    {  
        >       echo $currElement;  
        >       // mach noch mehr...  
        >    }  
        > }
        
        

        Hier ist Verzicht auf break angebracht. Der Code mit break ist komplizierter, aufwendiger und weniger verständlich.

        Freundliche Grüße

        Vinzenz

        1. Hallo Ingrid,

          » Die Break-Version sähe so aus:

          » ~~~php

          foreach($myArray as $currElement)

          » {
          »    if ($whatever)
          »    {

                    // Unbedingt erforderlich:  
                    // Kommentar der Form:  
                    // Ziel erreicht, die weiteren Arrayelemente müssen nicht mehr  
                    // betrachtet werden.  
            
          ~~~php
            
          
          > »       break;  
          > »    }  
          > »    echo $currElement;  
          > »    // mach noch mehr...  
          > » }
          
          

          » ~~~php

          » foreach($myArray as $currElement)
          » {
          »    if (!$whatever)
          »    {
          »       echo $currElement;
          »       // mach noch mehr...
          »    }
          » }

            
          
          > Hier ist Verzicht auf break angebracht. Der Code mit break ist komplizierter, aufwendiger und weniger verständlich.  
            
          das ist so natürlich nicht richtig - ich hatte continue im Kopf.  
          Aber: Code ohne Kommentare ist miserabler Code. Der Einsatz von break ist unbedingt zu kommentieren.  
            
            
          Freundliche Grüße  
            
          Vinzenz
          
          1. moin.

            »» Hier ist Verzicht auf break angebracht. Der Code mit break ist komplizierter, aufwendiger und weniger verständlich.

            das ist so natürlich nicht richtig - ich hatte continue im Kopf.
            Aber: Code ohne Kommentare ist miserabler Code. Der Einsatz von break ist unbedingt zu kommentieren.

            Freundliche Grüße

            Vinzenz

            Früher hat man gelernt, möglichst 1/3 Kommentare zu schreiben, aber in der Wirtschaft gibt es fast nur Kommentare, wenn es Außergewöhnliche Situationen im Code gibt. Bzw schwerer Verständliche Aktionen

            1. Hallo,

              » das ist so natürlich nicht richtig - ich hatte continue im Kopf.
              » Aber: Code ohne Kommentare ist miserabler Code. Der Einsatz von break ist unbedingt zu kommentieren.

              Früher hat man gelernt, möglichst 1/3 Kommentare zu schreiben, aber in der Wirtschaft gibt es fast nur Kommentare, wenn es Außergewöhnliche Situationen im Code gibt. Bzw schwerer Verständliche Aktionen

              was unwirtschaftlich ist, weil die Einarbeitung in den Bestandscode oftmals viel aufwendiger ist als den Code komplett neu zu schreiben :-)

              Freundliche Grüße

              Vinzenz

            2. Moin!

              Früher hat man gelernt, möglichst 1/3 Kommentare zu schreiben, aber in der Wirtschaft gibt es fast nur Kommentare, wenn es Außergewöhnliche Situationen im Code gibt. Bzw schwerer Verständliche Aktionen

              Das liegt daran, dass man gemerkt hat, dass die 1/3-Regel einfach der Sache nicht angemessen ist. Es geht nicht darum, irgendeine Mindestquote an Kommentartext in den Source zu schreiben, sondern darum, dass der Sourcecode verständlich ist.

              Das erreicht man nicht, indem man jeden Befehl, der für sich genommen schon eindeutig und klar ist, durch einen Kommentar ergänzt, der beschreibt, was dieser Befehl gerade macht:

              $i++; // i erhöhen

              Es geht vielmehr darum, dass an den Stellen, die durch den Programmcode nicht offensichtlich klar machen, was da getan wird, durch Kommentare eine Erklärung hinzugefügt wird.

              Wobei das ein zweischneidiges Schwert ist: Kommentare veralten sehr schnell, wenn sich der Code weiterentwickelt, denn es ist für den Programmablauf egal, ob der Kommentar noch zum Code passt, oder nicht. Kommentare werden dann gepflegt, wenn der Programmierer von dieser Pflege irgendeinen Vorteil hat. Beispielsweise, weil seine IDE ihm bei der Code-Completion den PHPDoc-Block einblendet, der zu der angefragten Funktion bzw. Methode gehört.

              - Sven Rautenberg

              1. Hallo,

                »» Früher hat man gelernt, möglichst 1/3 Kommentare zu schreiben, aber in der Wirtschaft gibt es fast nur Kommentare, wenn es Außergewöhnliche Situationen im Code gibt. Bzw schwerer Verständliche Aktionen
                Das liegt daran, dass man gemerkt hat, dass die 1/3-Regel einfach der Sache nicht angemessen ist. Es geht nicht darum, irgendeine Mindestquote an Kommentartext in den Source zu schreiben, sondern darum, dass der Sourcecode verständlich ist.

                ja, und dazu ist manchmal sogar ein höherer Anteil als 1/3 erforderlich, während es andere Fälle gibt, in denen der Programmcode weitgehend selbsterklärend ist. Sinnvoll gewählte Bezeichner für Variablen und Funktionen sind ein ganz wesentlicher Schritt in diese Richtung, manchmal sogar schon ausreichend.

                Das erreicht man nicht, indem man jeden Befehl, der für sich genommen schon eindeutig und klar ist, durch einen Kommentar ergänzt, der beschreibt, was dieser Befehl gerade macht:
                $i++; // i erhöhen

                Nein, das ist sinnlos, manchmal gar lächerlich.

                Es geht vielmehr darum, dass an den Stellen, die durch den Programmcode nicht offensichtlich klar machen, was da getan wird, durch Kommentare eine Erklärung hinzugefügt wird.

                Oder anders gesagt: Der Kommentar soll nicht erklären, was jeder einzelne Schritt elementar tut, sondern den Sinn der Anweisung erläutern.

                Wobei das ein zweischneidiges Schwert ist: Kommentare veralten sehr schnell, wenn sich der Code weiterentwickelt, denn es ist für den Programmablauf egal, ob der Kommentar noch zum Code passt, oder nicht.

                Ja sicher. Trotzdem habe ich es mir im Lauf der Jahre angewöhnt, bereits beim Schreiben des Codes reichlich zu kommentieren. Dabei entsteht der Kommentar anfangs aus den Vorüberlegungen (mit anderen Worten: Der Kommentar ist *vor* dem Code da!) und entwickelt sich mit dem Debugging.

                Mein Ziel ist, dass ein Leser auf der rechten Seite des Bildschirms oder des Blattes quasi im Klartext mitlesen kann, was der links davorstehende Code bezwecken soll. Voraussetzung ist, dass dieser Leser die verwendete Programmiersprache beherrscht und sich mit dem Zielsystem auskennt.
                Besondere Programmier-"Tricks" bedürfen dabei ebenso einer konkreten BEschreibung wie Vereinfachungen, etwa das Ausnutzen von Redundanzen oder von Bedingungen, die an anderer Stelle überprüft wurden.

                So long,
                 Martin

                --
                Wer schläft, sündigt nicht.
                Wer vorher sündigt, schläft besser.
        2. Hallo,

          Die Break-Version sähe so aus:

          foreach($myArray as $currElement)

          {
              if ($whatever)
              {
                 break;
              }
              echo $currElement;
              // mach noch mehr...
          }

          
          >   
          > > ~~~php
            
          
          > > foreach($myArray as $currElement)  
          > > {  
          > >    if (!$whatever)  
          > >    {  
          > >       echo $currElement;  
          > >       // mach noch mehr...  
          > >    }  
          > > }
          
          

          Hier ist Verzicht auf break angebracht. Der Code mit break ist komplizierter, aufwendiger und weniger verständlich.

          Ich finde, es kommt hier stark darauf an (egal ob nun break oder continue). Die if-Abfrage führt zu einer weiteren Verschachtelungsebene des ganzen Codes. Wenn der Code nur wenige Zeilen lang ist, ist das absolut kein Problem und ich stimme Dir zu, dass die if-Abfrage um den Gesamtcode die bessere Wahl ist. Wenn der Inhalt der Schleife aber relativ lang ist und noch weitere Verschachtelungsebenen enthält (z.B. eine innere Schleife), dann kann die Abfrage am Anfang der Schleife mit break/continue die Übersichtlichkeit erhöhen.

          Viele Grüße,
          Christian

      2. Hi!

        Switch (wie von Peter Pan eingeworfen) ist keine Schleife, betrifft also auch nicht die eigentliche Frage.

        Deshalb schrieb ich ja 'Kontrollstruktur'.
        Magst Du die Fragen nach 'if'-Schleifen alleine hier im Forum zählen?

        off:PP

        --
        "You know that place between sleep and awake, the place where you can still remember dreaming?" (Tinkerbell)
  2. Hi!

    da ich diese Diskussion in letzter Zeit mehrfach hatte, würde mich mal eure Meinung - soz. aus der harten Praxis - interessieren: was haltet ihr von break-Anweisungen innerhalb von Schleifen?

    Was spricht dagegen? Was dafür?

    Konkret geht es in unserem Fall um PHP!

    Was meinst Du _genau_?
    Bei der Kontrollstruktur switch kannst Du ja gerne auf break verzichten, aber Dir werden die Ergebnisse oft nicht gefallen.

    off:PP

    --
    "You know that place between sleep and awake, the place where you can still remember dreaming?" (Tinkerbell)
    1. Was meinst Du _genau_?
      Bei der Kontrollstruktur switch kannst Du ja gerne auf break verzichten, aber Dir werden die Ergebnisse oft nicht gefallen.

      Pfff! Wer benutzt schon switch? :-P

      --
      Reden ist Silber, Schweigen ist Gold, meine Ausführungen sind Platin.
      Self-Code: sh:( ch:? rl:( br:> n4:( ie:{ mo:) va:) de:> zu:} fl:| ss:| ls:~ js:|
  3. Hallo,

    was haltet ihr von break-Anweisungen innerhalb von Schleifen?
    Was spricht dagegen?

    PHP-Code mit einem Wert > 1 beim optionalen Argument tendiert dazu, unwartbar zu werden. Benötigt man es, ist der Code vermutlich zu kompliziert.

    Was dafür?

    es gibt Anwendungsfälle für break (auch außerhalb von switch, wo break nahezu unverzichtbar ist) und continue; Anwendungsfälle, wo der Verzicht auf break/continue zu komplexerem, unverständlicherem und weniger wartbarem Code führt.

    Freundliche Grüße

    Vinzenz

    1. Hallo Vinzenz

      »» was haltet ihr von break-Anweisungen innerhalb von Schleifen?
      »» Was spricht dagegen?

      PHP-Code mit einem Wert > 1 beim optionalen Argument tendiert dazu, unwartbar zu werden. Benötigt man es, ist der Code vermutlich zu kompliziert.

      Wie meinst du das?

      Danke dir,
      Martin

      1. echo $begrüßung;

        » PHP-Code mit einem Wert > 1 beim optionalen Argument tendiert dazu, unwartbar zu werden. Benötigt man es, ist der Code vermutlich zu kompliziert.
        Wie meinst du das?

        break hat ein optionales Argument, mit dem man angeben kann, wieviele Kontrollstrukturen man beenden möchte, so diese geschachtelt sind.

        echo "$verabschiedung $name";

        1. Hallo dedlfix,

          break hat ein optionales Argument, mit dem man angeben kann, wieviele Kontrollstrukturen man beenden möchte, so diese geschachtelt sind.

          Danke! Hatte ich schon ganz vergessen, hab ich zum Glück nie benutzt ;-)

          Martin

  4. da ich diese Diskussion in letzter Zeit mehrfach hatte, würde mich mal eure Meinung - soz. aus der harten Praxis - interessieren: was haltet ihr von break-Anweisungen innerhalb von Schleifen?

    Was spricht dagegen? Was dafür?

    Was sollte dagegen sprechen? Früher (zu Zeiten des C64) hieß es mal es wäre schlecht, weil der Stack nicht richtig aufgeräumt wird, wobei ich nicht weiß ob das je gestimmt hat.

    Konkret geht es in unserem Fall um PHP!

    Ich wüßte gar nicht warum man darüber diskutieren muss, wenn die Schleife ihren Sinn erfüllt hat, dann bricht man sie ab, fertig.

    Sauberer (in dem Sinn wie es Vinzenz meint) ist es aber in so einem Fall  - wenn es geht - eine while Schleife, mit einer Abbruchbedingung zu benutzen.

    Struppi.

    1. echo $begrüßung;

      Früher (zu Zeiten des C64) hieß es mal es wäre schlecht, weil der Stack nicht richtig aufgeräumt wird, wobei ich nicht weiß ob das je gestimmt hat.

      Kann ich mir nicht vorstellen, denn dann müsste es jede Menge Folgefehler gehagelt haben, denn jeder verlässt sich darauf, den Stack so vorzufinden, wie er ihn beim Aufruf einer Unterroutine hinterlassen hat.

      echo "$verabschiedung $name";

  5. Moin.

    Die seit anno domini gegen goto angeführten Argumente lassen sich zu einem gewissen Maß auf alle Sprung-Anweisungen übertragen, d.h. break und continue in Schleifen, aber auch multiple return-Anweisungen in einer Funktion und insbesondere auch throw in Sprachen mit expliziter Fehlerbehandlung.

    Trotzdem gibt es für all diese Anweisungen sinnvolle Anwendungen, die sich meist um die Behandlung außergewöhnlicher Situationen drehen. Grundsätzlich sollte eine Schleife beendet werden, wenn eine vorgegebene Abbruchsbedingung erreicht wurde. Außergewöhnliche Vorgänge, die den normalen Programmablauf unterbrechen, lassen sich jedoch häufig am einfachsten durch eine Sprung-Anweisung behandeln.

    Christoph

    1. Hallo,

      Die seit anno domini gegen goto angeführten Argumente lassen sich zu einem gewissen Maß auf alle Sprung-Anweisungen übertragen, d.h. break und continue in Schleifen

      naja, die Verallgemeinerung ist mir doch etwas zu allgemein. Die goto-Anweisung -wenn die Sprache sie bietet- würde ich allein deshalb vermeiden, weil sie den Sprung *an eine beliebige Stelle* im Code ermöglicht. Ich hatte in den letzten 20 Jahren höchstens zwei- oder dreimal das Bedürfnis, ein goto einzusetzen, also in sehr, sehr seltenen Ausnahmefällen.
      Den Einsatz von break und continue in Schleifen halte ich dagegen für völlig legitim, wenn er entsprechend dokumentiert und kenntlich gemacht wird. Da möchte ich Vinzenz unbedingt zustimmen.

      Im Gegensatz zum goto führen break und continue den Programmfluss nämlich an eine genau definierte Stelle zurück: Ans Ende bzw. an den Anfang einer Schleife.

      aber auch multiple return-Anweisungen in einer Funktion

      ... halte ich für völlig in Ordnung. Es liegt oft in der Natur der Sache, dass sich innerhalb der Funktion mehrere, voneinander unabhängige Zweige ergeben, deren Kontrollfluss von der Logik innerhalb der Funktion nicht mehr konvergiert. In jedem dieser Zweige halte ich ein return dann für angemessen und richtig, wenn das Ergebnis feststeht und keine weiteren Aktionen mehr notwendig sind; die Konvergenz des Kontrollflusses findet dann im aufrufenden Code statt. Sogar ein switch-Konstrukt, in dem jeder Zweig mit return anstatt mit break beendet wird, finde ich in bestimmten Situationen absolut okay.

      und insbesondere auch throw in Sprachen mit expliziter Fehlerbehandlung.

      Das nutze ich selbst auch nur sehr ungern, weil ich da den Eindruck habe, dass die Nachvollziehbarkeit des Codes leidet - das mag aber auch mein subjektiver Eindruck sein.

      Trotzdem gibt es für all diese Anweisungen sinnvolle Anwendungen, die sich meist um die Behandlung außergewöhnlicher Situationen drehen. Grundsätzlich sollte eine Schleife beendet werden, wenn eine vorgegebene Abbruchsbedingung erreicht wurde. Außergewöhnliche Vorgänge, die den normalen Programmablauf unterbrechen, lassen sich jedoch häufig am einfachsten durch eine Sprung-Anweisung behandeln.

      Volle Zustimmung.

      So long,
       Martin

      --
      Auf jeden Menschen auf der ganzen Welt entfallen statistisch gesehen etwa 3000 Spinnen, wie Wissenschaftler jetzt festgestellt haben.
      Wer will meine haben? Denn ich will sie bstimmt nicht.
      1. Hallo Martin,

        und insbesondere auch throw in Sprachen mit expliziter Fehlerbehandlung.

        Das nutze ich selbst auch nur sehr ungern, weil ich da den Eindruck habe, dass die Nachvollziehbarkeit des Codes leidet - das mag aber auch mein subjektiver Eindruck sein.

        Es kommt darauf an. Es stimmt, dass Exceptions oft nicht korrekt verstanden werden und daher falsch eingesetzt werden - und dann passiert genau das, was Du gerade monierst: Code wird unwartbar. Richtig eingesetzt sind Exceptions jedoch (zumindest in meinen Augen) eine enorme Hilfe bei der Fehlerbehandlung.

        Viele Grüße,
        Christian

    2. Hallo Christoph,

      Die seit anno domini gegen goto angeführten Argumente lassen sich zu einem gewissen Maß auf alle Sprung-Anweisungen übertragen, d.h. break und continue in Schleifen, aber auch multiple return-Anweisungen in einer Funktion und insbesondere auch throw in Sprachen mit expliziter Fehlerbehandlung.

      Klar, break/continue/throw sind nichts anderes als etwas abstrahierte goto-Statements. Das ist in meinen Augen aber auch nichts schlimmes, goto per se halte ich nicht für böse. Wenn ich beispielsweise Code habe, der etwas tun soll, am Ende aber zwanngsweise bestimmte Dinge aufräumen soll, dann ist goto hierfür keine schlechte Wahl (andere Programmiersprachen erfinden dafür z.B. "finally", was im Endeffekt auch nur eine Abstraktion ist).

      Goto wird eigentlich nur dann problematisch, wenn man Dinge tut, die das Verständnis erschweren. Wenn ein goto (oder entsprechend halt ein break/continue/sonstwas) aber an einer Stelle die einfachste *verständlichste* Möglichkeit ist, etwas zu lösen, dann sollte man davon in meinen Augen durchaus davon gebrauch machen.

      Goto ist nur deswegen so extrem verpönt, weil typische Programme von vor Jahrzehnten fast ausschließlich mit Goto geschrieben wurden - und damit der Code sehr unübersichtlich wurde. Wenn man eine Schleife mit Goto nachbaut und dann am besten auch noch wild aus der Schleife heraus und anschließend wieder in die Schleife hineinspringt, dann macht man natürlich etwas falsch und der Code ist Schrott.

      Man sollte jedoch nicht davor zurückschrecken, goto in gesunden Dosen dort einzusetzen, wo es wirklich sinnvoll ist: Ans Ende einer Funktion zur Fehlerbehandlung springen, in etwas abstrakterer Form als break/continue, ...

      Hängt natürlich auch von der jeweiligen Programmiersprache und den dort enthaltenen Konzepten ab, wie genau man bestimmte Dinge realisiert.

      Ferner: Spaghetticode habe ich auch schon mit OOP gesehen, wo verschiedenen Methoden sich komplett wirr gegenseitig aufrufen und keiner mehr durchblickt, was wo wie geschieht - für schlechten Code braucht's kein goto, das bekommen die Leute, die's drauf anlegen, auch anders hin. ;-)

      Viele Grüße,
      Christian

      1. Moin!

        Ferner: Spaghetticode habe ich auch schon mit OOP gesehen, wo verschiedenen Methoden sich komplett wirr gegenseitig aufrufen und keiner mehr durchblickt, was wo wie geschieht - für schlechten Code braucht's kein goto, das bekommen die Leute, die's drauf anlegen, auch anders hin. ;-)

        Würde das in jedem Fall unterstreichen.

        Man kann jede Schleifenkonstruktion so neu schreiben (refactoring), dass enthaltene Anweisungen wie break und continue überflüssig werden. Umgekehrt kann man Schleifen, die diese Anweisungen vermeiden, natürlich auch so umschreiben, dass break und continue genutzt werden. Das Resultat sei jeweils identisch.

        Die Frage ist jeweils, warum man die eine oder die andere Richtung beschreiten sollte. Und als Antwort kann eigentlich nur gültig sein: Um die Klarheit des Codes zu verstärken.

        Wenn man sich durch geschickten Einsatz eines gut platzierten continue oder break die zusätzliche Einrückungsebene einer den gesamten Schleifeninhalt klammernden IF-Abfrage ersparen kann, oder dadurch sämtliche Abbruchbedingungen sauber an den Anfang der Schleife platziert, bevor darunter dann der komplexere Arbeitsteil kommt, dann dient das eindeutig der Klarheit des programmierten Codes und wäre zu bevorzugen.

        - Sven Rautenberg

        1. echo $begrüßung;

          Man kann jede Schleifenkonstruktion so neu schreiben (refactoring), dass enthaltene Anweisungen wie break und continue überflüssig werden. [...]

          Wenn wir schon mal beim Thema sind - da hatte ich neulich das Problem in C# in einem switch ein foreach beenden zu wollen. Das break im switch wirkt aber nur auf selbiges und höchstens ein continue, das im switch nicht vorkommt, hätte auf das foreach gewirkt. Doch ich wollte ja abbrechen und nicht zum nächsten Durchlauf übergehen.

          Beim Hinzufügen eines Elements zu this.elements sind diverse Bedingungen (this.Contraints) zu beachten. Jede Bedingung kann ergeben (constraint.Satisfies(...)), dass

          • das Element auf jeden Fall hinzugefügt werden darf, egal wie die anderen Antworten ausfallen (Allowed),
          • das Element nicht hinzugefügt werden darf (Veto),
          • das Element hinzugefügt werden darf (Vote)
          • Stimmenthaltung vorliegt (IgnoreMe).
            Und zwar in der angegebenen Priorität von oben nach unten.
            Der answers.TrueForAll(...)-Aufruf ergibt true wenn kein false-Eintrag enthalten ist, also auch bei leerer Liste. Constraint.Results ist ein enum-Typ mit den oben aufgelistet und in den cases zu sehenden Mitgliedern. Der Rest ist hoffentlich auch ohne C#-Kenntnisse verständlich.
          void AddElement(Element element) {  
            List<bool> answers = new List<bool>();  
            foreach (Constraint constraint in this.Constraints)  
              switch (constraint.Satisfies(element, this)) {  
                case Constraint.Results.Allowed:  
                  answers.Clear(); // discard all other answers  
                  goto Allowed; // and break out of foreach  
                case Constraint.Results.Veto:  
                  answers.Add(false);  
                  break;  
                case Constraint.Results.Vote:  
                  answers.Add(true);  
                  break;  
                case Constraint.Results.IgnoreMe:  
          	break;  
                default:  
                  throw new NotSupportedException();  
              }  
            
          Allowed:  
            // either Allowed or at least one constraint has to vote, but nobody must veto.  
            if (answers.TrueForAll(delegate(bool answer) { return answer; }))  
              this.elements.Add(element);  
            else  
              throw new ArgumentException("Can't add element due to constraint restrictions.");  
          }
          

          Gibt es andere Lösungsvorschläge und wenn ja, was ist daran besser als bei meiner Implementation?

          echo "$verabschiedung $name";

          1. Moin.

            Gibt es andere Lösungsvorschläge und wenn ja, was ist daran besser als bei meiner Implementation?

            Falls ich den Code richtig verstanden haben, kann deine answers-Liste durch eine einfache boolsche Variable ersetzt werden:

              
            void AddElement(Element element) {  
                bool vetoed = false;  
              
                foreach(Constraint constraint in this.Constraints) {  
                    switch(constraint.Satisfies(element, this)) {  
                        case Constraint.Results.Allowed:  
                        goto AddElement;  
              
                        case Constraint.Results.Veto:  
                        vetoed = true;  
                        break;  
              
                        case Constraint.Results.Vote:  
                        case Constraint.Results.IgnoreMe:  
                        break;  
              
                        default:  
                        throw new NotSupportedException();  
                    }  
                }  
              
                if(vetoed) throw new ArgumentException(  
                    "Can't add element due to constraint restrictions.");  
              
                AddElement:  
                this.elements.Add(element);  
            }  
            
            

            Den Test if(vetoed) könnte man auch hinter die Sprungmarke verschieben, dann müsste man im Fall Constraint.Results.Allowed noch vetoed = false ergänzen; der Algorithmus wäre in diesem Fall eine 1:1-Übersetzung deiner Version.

            Christoph

            1. echo $begrüßung;

              Falls ich den Code richtig verstanden haben, kann deine answers-Liste durch eine einfache boolsche Variable ersetzt werden:

              Ja, das wäre eine Vereinfachung (für den geposteten Fall), aber das goto ist immer noch drin.

              Allerdings fällt mit gerade auf, dass ich beim Übertragen ins Forum schon eine undurchdachte Vereinfachung eingebaut habe, so dass meine ursprüngliche Aufgabenstellung nicht mehr erfüllt wird, was daran zu sehen ist, dass der Kommentar

              // either Allowed or at least one constraint has to vote, but nobody must veto.

              nicht mehr zum Code passt [1]. So sah das ursprünlich aus:

              case Constraint.Results.Allowed:
                      answers.Clear(); // discard all other answers
                      answers.Add(true); // only one vote for true
                      goto Allowed; // and break out of foreach
              ...
              Allowed:
                // either Allowed or at least one constraint has to vote, but nobody must veto.
                if (answers.Count > 0 && answers.TrueForAll(delegate(bool answer) { return answer; }))
                  this.elements.Add(element);

              Und in dem Fall brauchts dann meiner Meinung nach schon zwei bools. Eins das anzeigt, ob ein Veto existiert und eins das bei einem Vote auf true geht. Den Allowed-Fall kann man mit veto=false; vote=true; goto Allowed; erledigen. Und die Auswertung wird auch einfacher:

              if (vote && !veto)
                  this.elements.Add(element);

              Insgesamt schon resourcenschonender als die bool-Liste - danke für die Anregung - aber leider noch mit goto.

              Man könnte das switch durch eine if-else-if-Kette ersetzen und hätte dann das break frei für das foreach, aber das gefällt mir auch nicht besser als das goto.

              [1] Mit TDD wär das nicht passiert.[2]
              [2] Ausrede: Unit Tests sind in dem mir zur Verfügung stehenden VS 2005 noch nicht eingebaut.

              echo "$verabschiedung $name";

              1. Moin.

                Und in dem Fall brauchts dann meiner Meinung nach schon zwei bools.

                Sehe ich auch so - oder einen Datentyp, der (mindestens) drei Zustände beschreiben kann.

                Den Allowed-Fall kann man mit veto=false; vote=true; goto Allowed; erledigen.

                Oder, wie in 'meiner' Version, einen direkten Sprung zur Element-Hinzufügung (es ist schon spät bzw. noch ziemlich früh, etwaige sprachliche Fehlgriffe möge man mir verzeihen ;))

                Man könnte das switch durch eine if-else-if-Kette ersetzen und hätte dann das break frei für das foreach, aber das gefällt mir auch nicht besser als das goto.

                Bei geschachtelten Kontrollstrukturen kommt man meines Wissens nach in C# nicht um goto herum; in Java hätte man der Schleife ein Label verpassen und diese dann gezielt per break verlassen können.

                Christoph

              2. Hi,

                [2] Ausrede: Unit Tests sind in dem mir zur Verfügung stehenden VS 2005 noch nicht eingebaut.

                ??? Na dann halt mit NUnit (und evt noch NAnt), vielleicht ein bis zwei Tage Arbeit, die Scripts aufzusetzen.

                Überigens: Ich habe in C# noch nie "Sprungmarken" benutzt und ich programmiere damit schon seit 2002 herum.

                Ciao, FF

                1. echo $begrüßung;

                  Überigens: Ich habe in C# noch nie "Sprungmarken" benutzt und ich programmiere damit schon seit 2002 herum.

                  Das ist auch meine erste. Wie würdest du das ohne goto lösen?

                  echo "$verabschiedung $name";

                  1. Moin.

                    Wie würdest du das ohne goto lösen?

                    Z.B. durch Hinzufügen eoiner weiteren boolschen Variable, die bei Bedarf ein break hinter dem switch auslöst:

                      
                    void AddElement(Element element) {  
                        bool vetoed = false;  
                        bool voted = false;  
                        bool allowed = false;  
                      
                        foreach(Constraint constraint in this.Constraints) {  
                            switch(constraint.Satisfies(element, this)) {  
                                case Constraint.Results.Allowed:  
                                allowed = true:  
                                break;  
                      
                                case Constraint.Results.Veto:  
                                vetoed = true;  
                                break;  
                      
                                case Constraint.Results.Vote:  
                                voted = true;  
                                break;  
                      
                                case Constraint.Results.IgnoreMe:  
                                break;  
                      
                                default:  
                                throw new NotSupportedException();  
                            }  
                      
                            if(allowed) break;  
                        }  
                      
                        if(allowed || (voted && !vetoed))  
                            this.elements.Add(element);  
                        else throw new ArgumentException(  
                            "Can't add element due to constraint restrictions.");  
                    }  
                    
                    

                    Meiner Meinung nach macht das die Sache aber nicht wirklich besser...

                    Eine andere Möglichkeit wäre, dies Nebenbedingung allowed == true in die Abbruchsbedingung der Schleife zu integrieren. Dazu müsste man meines (sehr begrenzten) Wissens nach die foreach-Schleife duch eine for-Schleife mit explizitem IEnumerator ersetzen.

                    Christoph

                  2. » Überigens: Ich habe in C# noch nie "Sprungmarken" benutzt und ich programmiere damit schon seit 2002 herum.

                    Das ist auch meine erste. Wie würdest du das ohne goto lösen?

                    Ich programmier ja meistens mit Perl und da gibt es kein switch, was ist denn an if-else so schlimm?
                    Das ist doch allemal besser als ein goto oder eine eigentlich überflüssige Variabel zu benutzen. Ausserdem wäre der Code kürzer.

                    Struppi.

                    1. echo $begrüßung;

                      Ich programmier ja meistens mit Perl und da gibt es kein switch, was ist denn an if-else so schlimm?

                      Daran ist "schlimm", dass der Ausdruck in jedem if neu berechnet werden muss. Ich hab da ja einen Aufruf der Methode constraint.Satisfies() drin. Die soll nicht mehrfach immer wieder das gleiche berechnen. Man müsste dann noch eine Variable mit dem Zwischenergebnis erstellen, welches dann von den ifs verglichen wird.

                      Das ist doch allemal besser als ein goto oder eine eigentlich überflüssige Variabel zu benutzen. Ausserdem wäre der Code kürzer.

                      Nö, die "überflüssige Variable" wird nur für was anderes verwendet und der Code bleibt bei 1TBS-Notation gleich lang. Die switch-Zeile erstellt die Zwischenergebnisvariable, case wird zu if und die case-breaks werden zu "} else". Das } vom switch verschwindet, das wars aber auch schon. Und man sieht nicht mehr auf einen Blick, dass das Ergebnis von Satisfies() auf unterschiedliche Werte geprüft werden soll.

                      echo "$verabschiedung $name";

                  3. Hallo,

                    hmm ... da müsste ich noch mal durchlesen, was genau passieren soll ... hab es nur überflogen und bin am TDD hängengeblieben. ;)

                    Im Moment hab ich leider grad kurze Elle auf Arbeit, aber ich kanns mir mal übers Wochenende anschauen. Auf den ersten Blick würde ich ein FlagsAttribute() Enum vorschlagen und drauf das Switch-Case.

                    Cheers, Frank

      2. habe d'ehre Christian

        Goto ist nur deswegen so extrem verpönt, weil typische Programme von vor Jahrzehnten fast ausschließlich mit Goto geschrieben wurden - und damit der Code sehr unübersichtlich wurde.

        Früher weit verbreitet bei COBOL und RPG auf IBM-Maschinen. Bei 10.000 Zeilen Code sucht man sich da einen Wolf. *grusel*

        man liest sich
        Wilhelm