Mein Chef erwähnt immer wieder nonchalant, dass schlechte Programmierer break
und continue
in Schleifen arbeiten.
Ich benutze sie die ganze Zeit, weil sie einen Sinn ergeben. Lassen Sie sich von mir inspirieren:
function verify(object) {
if (object->value < 0) return false;
if (object->value > object->max_value) return false;
if (object->name == "") return false;
...
}
Der Punkt hier ist, dass zuerst die Funktion prüft, ob die Bedingungen korrekt sind, und dann die tatsächliche Funktionalität ausführt. IMO gilt das gleiche mit Schleifen:
while (primary_condition) {
if (loop_count > 1000) break;
if (time_exect > 3600) break;
if (this->data == "undefined") continue;
if (this->skip == true) continue;
...
}
Ich denke, das erleichtert das Lesen & Debuggen; aber ich sehe auch keinen Nachteil.
goto
) in einigen Fällen nützlich sind.Antworten:
Wenn sie zu Beginn eines Blocks verwendet werden, wirken sie wie Vorbedingungen, wenn die ersten Überprüfungen durchgeführt werden. Das ist also gut.
Wenn sie in der Mitte des Blocks mit etwas Code verwendet werden, wirken sie wie versteckte Fallen, also ist es schlecht.
quelle
Sie können Donald Knuths 1974 erschienenen Artikel Structured Programming with go to Statements lesen , in dem er verschiedene
go to
strukturell wünschenswerte Verwendungen des beschreibt . Sie enthalten das Äquivalent vonbreak
undcontinue
Anweisungen (viele der darin enthaltenen Verwendungengo to
wurden zu eingeschränkteren Konstrukten entwickelt). Ist Ihr Chef der Typ, der Knuth einen schlechten Programmierer nennt?(Die angegebenen Beispiele interessieren mich. Typischerweise
break
undcontinue
werden von Leuten abgelehnt, die einen Ein- und Ausstieg aus einem Code-Teil mögen, und diese Art von Person runzelt auch die Stirn bei mehrerenreturn
Aussagen.)quelle
Break
,Continue
undExit
als Werkzeuge in meinem Werkzeugkasten; Ich benutze sie dort, wo es das Verfolgen des Codes erleichtert, und benutze sie nicht dort, wo es das Lesen erschweren würde.Ich glaube nicht, dass sie schlecht sind. Die Idee, dass sie schlecht sind, stammt aus der Zeit der strukturierten Programmierung. Es hängt mit der Vorstellung zusammen, dass eine Funktion einen einzelnen Eintrittspunkt und einen einzelnen Austrittspunkt haben muss, dh nur einen
return
pro Funktion.Dies ist sinnvoll, wenn Ihre Funktion lang ist und Sie mehrere verschachtelte Schleifen haben. Ihre Funktionen sollten jedoch kurz sein und Sie sollten Schleifen und ihre Körper in eigene kurze Funktionen einwickeln. Im Allgemeinen kann das Erzwingen eines einzelnen Austrittspunkts für eine Funktion zu einer sehr verworrenen Logik führen.
Wenn Ihre Funktion sehr kurz ist, wenn Sie eine einzelne Schleife haben oder im schlimmsten Fall zwei verschachtelte Schleifen, und wenn der Schleifenkörper sehr kurz ist, ist es sehr klar, was a
break
oder acontinue
tut. Es ist auch klar, was mehrerereturn
Anweisungen bewirken.Diese Probleme werden in "Clean Code" von Robert C. Martin und in "Refactoring" von Martin Fowler behandelt.
quelle
CALL P(X, Y, &10)
, und im Fehlerfall könnte die Funktion die Steuerung an diese Anweisung übergeben, anstatt zum Punkt des Aufrufs zurückzukehren.Schlechte Programmierer sprechen absolut (genau wie Sith). Gute Programmierer verwenden die klarste mögliche Lösung ( alle anderen Dinge sind gleich ).
Wenn Sie break and continue häufig verwenden, ist es schwierig, dem Code zu folgen. Wenn es jedoch schwieriger wird, den Code zu ersetzen, ist dies eine schlechte Änderung.
Das Beispiel, das Sie gegeben haben, ist definitiv eine Situation, in der die Pausen und Fortsetzungen durch etwas Eleganteres ersetzt werden sollten.
quelle
Die meisten Leute halten es für eine schlechte Idee, weil das Verhalten nicht leicht vorhersehbar ist. Wenn Sie den Code durchlesen und
while(x < 1000){}
davon ausgehen, dass er bis x> = 1000 ausgeführt wird ... Wenn sich jedoch Pausen in der Mitte befinden, stimmt dies nicht, sodass Sie Ihrem Code nicht wirklich vertrauen können Looping ...Es ist der gleiche Grund, warum die Leute GOTO nicht mögen: Sicher, es kann gut verwendet werden, aber es kann auch zu furchterregendem Spaghetti-Code führen, bei dem der Code zufällig von Abschnitt zu Abschnitt springt.
Wenn ich eine Schleife machen würde, die unter mehr als einer Bedingung unterbrochen wurde, würde ich
while(x){}
X auf false setzen, wenn ich ausbrechen musste. Das Endergebnis wäre dasselbe, und jeder, der den Code durchliest, würde wissen, dass er die Dinge, die den Wert von X veränderten, genauer betrachten muss.quelle
while(notDone){ }
Annäherung.break;
durchx=false;
wird Ihr Code nicht klarer. Sie müssen den Body noch nach dieser Aussage durchsuchen. Und im Falle von müssenx=false;
Sie überprüfen, dass es nichtx=true;
weiter unten trifft .while (x < 1000)
gehe ich davon aus, dass es 1000-mal ausgeführt wird". Nun, es gibt viele Gründe, warum das falsch ist, auch wennx
es anfänglich null ist. Wer sagt zum Beispiel, dassx
während der Schleife genau einmal inkrementiert und niemals auf andere Weise geändert wird? Selbstx >= 1000
wenn Sie davon ausgehen, dass eine bestimmte Menge nicht das Ende der Schleife bedeutet, wird sie möglicherweise in den Bereich zurückgesetzt, bevor die Bedingung überprüft wird.Ja, Sie können Programme ohne break-Anweisungen [neu] schreiben (oder aus der Mitte von Schleifen zurückkehren, die dasselbe tun). Möglicherweise müssen Sie jedoch zusätzliche Variablen und / oder Codeduplizierungen einführen, die das Verständnis des Programms in der Regel erschweren. Pascal (die Programmiersprache) war aus diesem Grund besonders für Anfängerprogrammierer sehr schlecht. Ihr Chef möchte im Grunde, dass Sie in Pascals Kontrollstrukturen programmieren. Wenn Linus Torvalds in Ihren Schuhen wäre, würde er Ihrem Chef wahrscheinlich den Mittelfinger zeigen!
Es gibt ein Ergebnis der Informatik namens Kosarajus Hierarchie der Kontrollstrukturen, das aus dem Jahr 1973 stammt und in Knuths (berühmterem) Aufsatz über GOTOS aus dem Jahr 1974 erwähnt wird. (Dieser Aufsatz von Knuth wurde übrigens bereits oben von David Thornley empfohlen Was S. Rao Kosaraju 1973 bewiesen hat, ist, dass es nicht möglich ist, alle Programme mit mehrstufigen Unterbrechungen der Tiefe n in Programme mit einer Unterbrechungstiefe von weniger als n umzuschreiben, ohne zusätzliche Variablen einzuführen. Aber sagen wir, das ist nur ein rein theoretisches Ergebnis. (Fügen Sie einfach ein paar zusätzliche Variablen hinzu ?! Sicher können Sie das tun, um Ihrem Chef zu gefallen ...)
Was aus Sicht der Softwareentwicklung weitaus wichtiger ist, ist eine neuere Veröffentlichung von Eric S. Roberts aus dem Jahr 1995 mit dem Titel Loop Exits and Structured Programming: Reopening the Debate ( http://cs.stanford.edu/people/eroberts/papers/SIGCSE- 1995 / LoopExits.pdf ). Roberts fasst mehrere empirische Studien zusammen, die von anderen vor ihm durchgeführt wurden. Wenn zum Beispiel eine Gruppe von Schülern vom Typ CS101 gebeten wurde, Code für eine Funktion zu schreiben, die eine sequentielle Suche in einem Array implementiert, sagte der Autor der Studie Folgendes zu den Schülern, die einen break / return / goto-Befehl verwendeten, um das Array zu verlassen die sequentielle Suchschleife, wenn das Element gefunden wurde:
Roberts sagt auch, dass:
Ja, Sie sind vielleicht erfahrener als CS101-Studenten, aber ohne die break-Anweisung (oder gleichwertig return / goto from the middle of loops) zu verwenden, schreiben Sie irgendwann Code, der zwar nominell schön strukturiert ist, aber in Bezug auf zusätzliche Logik haarig genug ist Variablen und Code-Vervielfältigung, die jemand, wahrscheinlich Sie selbst, mit Logikfehlern behebt, während er versucht, dem Codierungsstil Ihres Chefs zu folgen.
Ich werde hier auch sagen, dass Roberts 'Artikel für den durchschnittlichen Programmierer weitaus zugänglicher ist, also eine bessere erste Lektüre als die von Knuth. Es ist auch kürzer und deckt ein engeres Thema ab. Sie könnten es wahrscheinlich sogar Ihrem Chef empfehlen, selbst wenn er eher das Management als der CS-Typ ist.
quelle
Ich denke nicht darüber nach, eine dieser schlechten Methoden zu verwenden, aber wenn Sie sie zu oft in derselben Schleife verwenden, sollte die Logik, die in der Schleife verwendet wird, überdacht werden. Verwenden Sie sie sparsam.
quelle
Das Beispiel, das Sie gegeben haben, benötigt keine Pausen und fährt auch nicht fort:
Mein "Problem" mit den 4 Zeilen in Ihrem Beispiel ist, dass sie alle auf der gleichen Ebene sind, aber unterschiedliche Aufgaben haben: Einige brechen, andere fahren fort ... Sie müssen jede Zeile lesen.
In meinem verschachtelten Ansatz wird der Code umso nützlicher, je tiefer Sie gehen.
Aber wenn Sie tief im Inneren einen Grund finden würden, die Schleife zu stoppen (außer der Primärbedingung), wäre eine Unterbrechung oder Rückkehr sinnvoll. Ich würde das der Verwendung eines zusätzlichen Flags vorziehen, das im Top-Level-Zustand getestet werden soll. Die Pause / Rückkehr ist direkter; Es gibt die Absicht besser an, als eine weitere Variable zu setzen.
quelle
<
Vergleiche<=
mit der OPs-LösungDie "Schlechtigkeit" hängt davon ab, wie Sie sie verwenden. In der Regel verwende ich Unterbrechungen in Schleifenkonstrukten NUR dann, wenn sie mir Zyklen ersparen, die durch ein Refactoring eines Algorithmus nicht gespeichert werden können. Beispiel: Durchsuchen Sie eine Sammlung nach einem Element, dessen Wert in einer bestimmten Eigenschaft auf true festgelegt ist. Wenn Sie nur wissen müssen, dass für eines der Elemente diese Eigenschaft auf true festgelegt wurde, ist eine Unterbrechung hilfreich, um die Schleife entsprechend zu beenden.
Wenn die Verwendung einer Unterbrechung das Lesen des Codes nicht besonders erleichtert, die Ausführung verkürzt oder die Verarbeitungszyklen erheblich spart, sollten Sie sie am besten nicht verwenden. Ich neige dazu, auf den "kleinsten gemeinsamen Nenner" zu codieren, wenn dies möglich ist, um sicherzustellen, dass jeder, der mir folgt, meinen Code leicht einsehen und herausfinden kann, was los ist (ich bin dabei nicht immer erfolgreich). Pausen reduzieren das, weil sie ungerade Ein- / Ausstiegspunkte einführen. Missbräuchlich können sie sich sehr ähnlich verhalten wie eine aus dem Ruder gelaufene Aussage.
quelle
Absolut nicht ... Ja, die Verwendung von
goto
ist schlecht, weil es die Struktur Ihres Programms verschlechtert und es auch sehr schwierig ist, den Kontrollfluss zu verstehen.Aber die Verwendung von Aussagen wie
break
undcontinue
ist heutzutage absolut notwendig und keinesfalls als schlechte Programmierpraxis anzusehen.Und auch nicht so schwer zu verstehen, den Kontrollfluss bei der Verwendung von
break
undcontinue
. In Konstrukten wie diesem istswitch
diebreak
Anweisung unbedingt erforderlich.quelle
Der Grundgedanke ist, dass Sie Ihr Programm semantisch analysieren können. Wenn Sie einen einzelnen Eingang und einen einzelnen Ausgang haben, ist die Berechnung möglicher Zustände erheblich einfacher als wenn Sie Gabelpfade verwalten müssen.
Zum Teil spiegelt sich diese Schwierigkeit darin wider, dass Sie in der Lage sind, konzeptionell über Ihren Code nachzudenken.
Ehrlich gesagt ist Ihr zweiter Code nicht offensichtlich. Was macht es? Geht 'weiter' oder 'weiter' die Schleife? Ich habe keine Ahnung. Zumindest Ihr erstes Beispiel ist klar.
quelle
Ich würde Ihr zweites Code-Snippet durch ersetzen
nicht aus Gründen der Kürze - ich denke eigentlich, das ist einfacher zu lesen und für jemanden zu verstehen, was los ist. Im Allgemeinen sollten die Bedingungen für Ihre Schleifen nur in den Schleifenbedingungen enthalten sein, die nicht über den gesamten Körper verteilt sind. Es gibt jedoch einige Situationen , in denen
break
undcontinue
Lesbarkeit helfen können.break
mehr, alscontinue
ich hinzufügen könnte: Dquelle
foreach
Schleife, da hierdurch nur alle Elemente in einer Sammlung durchlaufen werden . Einefor
Schleife ist insofern ähnlich, als sie keinen bedingten Endpunkt haben sollte. Wenn Sie einen bedingten Endpunkt benötigen, müssen Sie einewhile
Schleife verwenden.break
meiner Meinung nach nur ein Maximum aus der Schleife geben.Ich bin nicht einverstanden mit Ihrem Chef. Es gibt geeignete Orte für
break
undcontinue
zum Gebrauch. Der Grund, warum Ausnahmen und Ausnahmebehandlungen in modernen Programmiersprachen eingeführt wurden, ist, dass Sie nicht jedes Problem mit nur lösen könnenstructured techniques
.Nebenbei möchte ich hier keine religiöse Diskussion beginnen, aber Sie könnten Ihren Code so umstrukturieren, dass er noch besser lesbar ist:
Auf einer anderen Seite beachten
Ich persönlich mag die Verwendung von
( flag == true )
in conditionals nicht, denn wenn die Variable bereits ein Boolescher Wert ist, führen Sie einen zusätzlichen Vergleich ein, der durchgeführt werden muss, wenn der Wert des Booleschen Werts die gewünschte Antwort hat - es sei denn, Sie sind sich sicher, dass Ihr Compiler dies tut optimieren Sie diesen zusätzlichen Vergleich weg.quelle
boolean
ist oder was die knappe / elegante Terminologie bedeutet, sollten Sie vielleicht besser ein paar klügere Betreuer einstellen ;-)Ich stimme deinem Chef zu. Sie sind schlecht, weil sie Methoden mit hoher zyklomatischer Komplexität erzeugen. Solche Methoden sind schwer zu lesen und schwer zu testen. Zum Glück gibt es eine einfache Lösung. Extrahieren Sie den Schleifenkörper in eine separate Methode, bei der "continue" zu "return" wird. "Rückkehr" ist besser, weil es nach "Rückkehr" vorbei ist - es gibt keine Sorgen um den lokalen Staat.
Für "break" extrahieren Sie die Schleife selbst in eine separate Methode und ersetzen Sie "break" durch "return".
Wenn die extrahierten Methoden eine große Anzahl von Argumenten erfordern, ist dies ein Hinweis darauf, dass eine Klasse extrahiert werden soll - sammeln Sie sie entweder in einem Kontextobjekt.
quelle
Ich denke, es ist nur ein Problem, wenn es tief in mehreren Schleifen verschachtelt ist. Es ist schwer zu wissen, zu welcher Schleife Sie wechseln. Es mag auch schwierig sein, einer Fortsetzung zu folgen, aber ich denke, der wahre Schmerz kommt von Pausen - die Logik kann schwierig zu befolgen sein.
quelle
break 2
; für andere denke ich, dass temporäre Bool-Flags verwendet werdenSolange sie nicht wie im folgenden Beispiel getarnt verwendet werden:
Mir geht es gut mit ihnen. (Beispiel in Produktionscode gesehen, meh)
quelle
Ich mag keinen dieser Stile. Folgendes würde ich bevorzugen:
Ich benutze wirklich nicht gerne
return
, um eine Funktion abzubrechen. Es fühlt sich an wie ein Missbrauch vonreturn
.Mit
break
auch ist nicht immer klar zu lesen.Besser noch könnte sein:
weniger Verschachtelung und die komplexen Bedingungen werden in Variablen umgestaltet (in einem echten Programm müssten Sie natürlich bessere Namen haben ...)
(Alle obigen Codes sind Pseudocodes)
quelle
break
undcontinue
. Das ungewöhnliche Beenden einer Schleife fühlt sich einfach komisch an und ich mag es nicht.continue
bedeutet, die Funktionalität überspringen, um zur nächsten Schleife zu gelangen; nicht "mit der Hinrichtung fortfahren"Nein. Es ist eine Möglichkeit, ein Problem zu lösen, und es gibt andere Möglichkeiten, es zu lösen.
Viele gängige Sprachen (Java, .NET (C # + VB), PHP, eigene Sprachen) verwenden "break" und "continue", um Schleifen zu überspringen. Sie beide "strukturierte goto (s)" Sätze.
Ohne sie:
Mit ihnen:
Beachten Sie, dass "break" - und "continue" -Code kürzer ist und "while" -Sätze normalerweise in "for" - oder "foreach" -Sätze umwandelt.
Beide Fälle sind eine Frage des Codierungsstils. Ich bevorzuge es, sie nicht zu verwenden , da ich durch den ausführlichen Stil mehr Kontrolle über den Code habe.
Ich arbeite tatsächlich in einigen Projekten, in denen es obligatorisch war, diese Sätze zu verwenden.
Einige Entwickler denken vielleicht, dass sie nicht unbedingt notwendig, aber hypothetisch sind. Wenn wir sie entfernen müssten, müssten wir auch "while" und "do while" entfernen ("repeat until", ihr Pascal-Typen) ;-)
Fazit, auch wenn ich sie lieber nicht benutze, denke ich, es ist eine Option, keine schlechte Programmierpraxis.
quelle
Ich bin nicht gegen
continue
undbreak
im Prinzip, aber ich denke , sie sind sehr Low-Level - Konstrukte , die sehr oft durch etwas noch besser ersetzt werden.Ich verwende hier C # als Beispiel und betrachte den Fall, dass eine Auflistung durchlaufen werden soll, aber wir möchten nur die Elemente, die ein Prädikat erfüllen, und wir möchten nicht mehr als maximal 100 Iterationen durchführen.
Das sieht AUSSERGEWÖHNLICH sauber aus. Es ist nicht sehr schwer zu verstehen. Ich denke, dass es eine Menge bringt, wenn man deklarativer ist. Vergleichen Sie es mit den folgenden:
Möglicherweise sollten die Where and Take-Aufrufe nicht einmal in dieser Methode enthalten sein. Vielleicht sollte diese Filterung durchgeführt werden, bevor die Sammlung an diese Methode übergeben wird. Auf jeden Fall wird klarer, was uns WIRKLICH interessiert, wenn wir uns von einfachen Dingen verabschieden und uns mehr auf die eigentliche Geschäftslogik konzentrieren. Es wird einfacher, unseren Code in zusammenhängende Module zu unterteilen, die sich mehr an gute Entwurfspraktiken halten und so weiter auf.
In einigen Teilen des Codes wird es immer noch Low-Level-Inhalte geben, aber wir möchten dies so weit wie möglich verbergen, da es mentale Energie erfordert, die wir verwenden könnten, um stattdessen über die geschäftlichen Probleme nachzudenken.
quelle
Code Complete enthält einen schönen Abschnitt über die Verwendung
goto
und mehrfache Rückkehr von Routine oder Schleife.Im Allgemeinen ist es keine schlechte Praxis.
break
odercontinue
genau sagen, was als nächstes passiert. Und dem stimme ich zu.Steve McConnell (Autor von Code Complete) verwendet fast dieselben Beispiele wie Sie, um die Vorteile der Verwendung verschiedener
goto
Anweisungen aufzuzeigen.Überbeanspruchung
break
oder kanncontinue
jedoch zu komplexer und nicht zu wartender Software führen.quelle