Laden...

gotos zum Verlassen einer geschachtelten Schleife 'böse'?

Erstellt von pdelvo vor 14 Jahren Letzter Beitrag vor 14 Jahren 1.636 Views
pdelvo Themenstarter:in
1.346 Beiträge seit 2008
vor 14 Jahren
gotos zum Verlassen einer geschachtelten Schleife 'böse'?

Hi,

ich habe eine kleinere Designfrage.

Auf dieser Seite steht, dass gotos nur in switch Statements gut sind. Wie vertrauenswürdig diese Quelle ist, weiß ich nicht.

http://www.blackwasp.co.uk/CSharpGoto.aspx

Wenn ich jetzt aber so einen Fall habe:

foreach(var a in b)
{
	foreach(var c in a)
	{
		if(c == d)
		{
			goto label;
		}
	}
	throw new Exception("...");
}

label:
...

Ist in diesem Fall ein goto angebracht? Ein If wäre da ein ziemlicher Overflow.

Gruß pdelvo

1.564 Beiträge seit 2007
vor 14 Jahren

Ja goto's sind böse!!

Sie lösen den sequenziellen Ablauf des Programms auf und machen Source-Code unverständlich.

Das einzige Szenario dass ich kenne (und manchmal anwende) sind CLEANUP Marken in C oder C++. In Sprachen die über einen GC verfügen kenne ich kein Argument für goto-Direktiven und habe sie auch noch nie gebraucht.

Grüße
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

pdelvo Themenstarter:in
1.346 Beiträge seit 2008
vor 14 Jahren

Was würdest du in diesem Fall vorschlagen?

Gruß pdelvo

1.564 Beiträge seit 2007
vor 14 Jahren

Hallo pdelvo

foreach(var a in b)  
{  
  foreach(var c in a)  
  {  
  	if(c == d)  
  	{  
  		goto label;  
  	}  
  }  
  throw new Exception("...");  
}  
  
label:  
...  

In dem Beispiel würde ich ein paar Sachen zur Verständlichkeit umstellen.
* Da die äußere Schleife zwingend nur einmal durchlaufen wird und entweder über goto oder eine Exception abgebrochen wird, würde ich das auch lesbar machen.

  • Statt der äußeren Schleife würde ich prüfen ob überhaupt Werte in der Collection sind
  • Mit First() kann man direkt das erste Element aus der Collection holen und über dessen Items loopen
    * Goto vermeidet man in dem Fall über eine äußere Boolean Variable. Wenn man nicht nur wissen will ob ein Wert vorhanden ist, sondern diesen auch haben will, kann man die entsprechende Variable normalerweise auf null prüfen.

Hier mein Ansatz:


         // Beispiel Liste
         List<List<int>> outer = new List<List<int>>
         {
            new List<int>{ 1, 2, 3 },
            new List<int>{ 4, 5 }
         };

         if (outer.Count != 0)
         {
            bool valid = false;

            foreach (var i in outer.First())
            {
               if (i == 2)
               {
                  valid = true;
                  break;
               }
            }

            if (!valid)
               throw new Exception("...");
         }

         // Weiter im Text

Ist zwar in dem speziellen Fall etwas mehr Code, läuft jetzt aber von oben nach unten und springt nicht mehr wild rum. 😉

Grüße
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

2.223 Beiträge seit 2005
vor 14 Jahren

Hallo pdelvo,

da ich schon in verschiedenen Programme, die in verschiedenen Basic Dialekten geschrieben wurden, gesehen und auch verändert habe,

die vor GOTO's nur so wimmelten.

Bin ich ein absoluter Gegner von Goto's, auch wenn es manchmal sinnvolle Anwendungen geben könnte.

zb. beim Failover von Switch-Case Anweisungen
oder beim verlassen einer tief verschachtelten Schleife.

Alles was mit einem Goto geht, kann man auch anders Lösen, selbst wenn es dadurch manchmal Komplizierter wird.

Was würdest du in diesem Fall vorschlagen

meine Empfehlung: nimm die If variante

Herzliche Grüße
BlackCoin

pdelvo Themenstarter:in
1.346 Beiträge seit 2008
vor 14 Jahren

Das tut mir jetzt leid. Der Code sollte so lauten:

foreach(var a in b)
{
    foreach(var c in a)
    {
        if(c == d)
        {
            goto label;
        }
    }
    throw new Exception("...");

label:
}

... 

Gruß pdelvo

1.044 Beiträge seit 2008
vor 14 Jahren

Hallo pdelvo,

gehen wir davon aus, dass du mehrere for-Schleifen ineinander verschachtelt hast, die z.B. eine Matrize mit Daten füllt. Nun möchtest du die untere for-Schleife beenden bzw. die komplette Rechnung abbrechen. Was nun? In solchen Fällen finde ich, dass eine goto-Anweisung genau das richtige ist.

Die goto-Anweisung ist natürlich nicht OOP, aber in machen Fällen sehr nützlich.

zero_x

pdelvo Themenstarter:in
1.346 Beiträge seit 2008
vor 14 Jahren

Genau so sehe ich das auch. Vorallem ist eine for schleife selber nur eine abfolge von gotos

Gruß pdelvo

3.430 Beiträge seit 2007
vor 14 Jahren

Hoi,

ich bin auch gegen die GOTO's denn diese sind wirklich böse.
So kann der Code schnell mal total kompliziert werden.

Sicherlich wäre es in diesem Fall nicht so, aber ma sollte GOTO einfach strickt vermeiden

zu deinem Beispiel


foreach(var a in b)
{
   bool found = false;
    foreach(var c in a)
    {
        if(c == d)
        {
            doOperationWhichIsAtLabel();
            found = true;
        }
    }

    if(!found)
        throw new Exception("...");
}

Also ich hätte das wahrscheinlich so gelöst

Gruss
MIchael

1.564 Beiträge seit 2007
vor 14 Jahren

Gleiches Konzept wie vorher:


         foreach (var a in b)
         {
            bool valid = false;

            foreach (var c in a)
            {
               if (c == d)
               {
                  valid = true;
                  break;
               }
            }

            if (!valid)
               throw new Exception("...");
         }

Grüße
Flo

Edit: Old man too slow... 😄

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

1.564 Beiträge seit 2007
vor 14 Jahren

Die goto-Anweisung ist natürlich nicht OOP, aber in machen Fällen sehr nützlich.

goto hat für mich nix mit OOP oder nicht OOP zu tun. Ich finde sie auch in C (Ausnahme vorher genannt), VB6 oder SQL unnötig. Manchmal mag ein anderer Weg etwas mehr Code erfordern, der Ablauf des Programms ist aber wesentlich besser zu verstehen.

Grüße
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

3.971 Beiträge seit 2006
vor 14 Jahren

Mache aus


foreach(var a in b)
{
    foreach(var c in a)
    {
        if(c == d)
        {
            goto label;
        }
    }
    throw new Exception("...");
}

ne eigeneständige Funktion und ersetze das goto einfach durch return.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

3.003 Beiträge seit 2006
vor 14 Jahren

Eigentlich heisst die Schleife, die durchlaufen wird, bis eine bestimmte Bedingung erfüllt ist, nicht foreach.

Nur so als Denkansatz.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo pdelvo,

bei sowas wünsche ich mir, dass du die Forensuche bemüht hättest. Das Thema goto produziert immer (unnötig) lange Threads, weil es zwei Lager gibt, die sich mehr oder weniger unversöhnlich gegenüberstehen. Das wird natürlich durch so eine pauschale Überschrift wie "gotos böse?" noch befördert. Ich habe den Titel daher zumindest mal auf den genannten Fall konkretisiert.

Es gibt genug Threads, in denen dieses Thema schon ausführlich behandelt wurde. Hier nur mal zwei davon.

2 Schleifen vorzeitig abbrechen
break für foreach aus einer switch anweisung

Daher sollten wir das Thema hier beenden.

herbivore