![]() |
Delphi-Version: 6
Verständnisfrage zu Exit
Als C/C++ Vorgeschädigter denke und schreibe ich immer noch ein result hin und erwarte das ende der Funktion. Nun, da Delphi ja bei einem result nicht die Funktion beendet, dachte ich exit zu benutzen, davor wird in der Delphi Basics Hilfe aber gewarnt. Was spricht eigentlich dagegen sowas zu schreiben und sich anzugewöhnen
Delphi-Quellcode:
Die ganzen nachkommenden else if Abfragen brauch ich ja nicht durchzugehen, wenn ich meine Funktion hier beenden will?
if A then begin
result := 1; exit; end else if B then... |
AW: Verständnisfrage zu Exit
Tust Du ja auch nicht:
Delphi-Quellcode:
Bei Deinem Beispiel ist das Exit schlicht überflüssig.
if A then begin
result := 1; end else if B then... // Else besagt doch: Nur wenn das vorherige nicht zutraf. Die Abfrage if b then wird also nicht ausgeführt. |
AW: Verständnisfrage zu Exit
Result in C++? Meinst du
Delphi-Quellcode:
?
return
Wie auch immer, gegen deinen Code spricht nichts. Außer dass du auch stattdessen schreiben könntest
Delphi-Quellcode:
.
Exit(1)
Zitat:
|
AW: Verständnisfrage zu Exit
Wenn die Bedingung wahr ist wird das else eh nicht abgearbeitet.
|
AW: Verständnisfrage zu Exit
Da gibt es unterschiedliche Auffassungen, die aber eher dem persönlichen Geschmack geschuldet sind.
Der Code sieht halt mit und ohne Exit unterschiedlich aus. Funktionelle Probleme bzw. Fehler gibt es durch Exit jedoch nicht. Du kannst mit Exit in einer Funktion auch direkt den Rückgabewert mitgeben.
Delphi-Quellcode:
Zu beachten ist, dass bei Exit in einem try-finally-Block in den finally-Abschnitt gesprungen wird (und danach - glaube ich - direkt aus der Methode).
if A then
begin Exit(1); end else if B then... |
AW: Verständnisfrage zu Exit
Naja, dann aber bitte so:
Delphi-Quellcode:
Wenn ich schon mit Exit rausspringe, kann ich mir die nachfolgende Else sparen.
if A then Exit(1);
if B then... |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Ja, aber hinter einem Exit in 'nem If then brauche ich keine Else. Die Alternative zu was soll denn da dann abgefragt werden, wenn die Alternative, zu der es ggfls. eine weitere geben könnte, bereits beschlossen hat, das hier ultimativ schluss iss? ;-)
@kagi3624 For-, Repeat, While-Schleifen kann man mit break verlassen. Inhaltlich nicht sinnvoll, aber für's Prinzip geeignet ;)
Delphi-Quellcode:
for i := 0 to MaxInt do begin
if i > Trunc(Now) then begin Result := i div 42; break; end; end; |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
oder
else
Delphi-Quellcode:
habe, dann weiß ich sofort, dass nur einer dieser Blöcke ausgeführt wird. Bei deiner Notation springt dies nicht ins Auge, vielmehr erfährt man erst durch Auswerten, dass der nachfolgende Code nicht ausgeführt wird. Das empfinde ich als deutlich weniger intuitiv.
end else if
|
AW: Verständnisfrage zu Exit
Aber in der Situation ist das Exit nicht (zwingend) erforderlich, da die Routine ohne das Exit zum gleichen Ergebnis führen würde.
Schreibtechnisch wird also ein Result := 1 durch Exit(1) ersetzt. Da finde ich die Zuweisung des Rückgabewertes an Result deutlich intuitiver als ein Exit, auch wenn es letztlich zum gleichen Ergebnis führt. Exit nutze ich persönlich nur, wenn ich in 'ner Fehlersituation (also im Exceptblock eines Trys) aus 'ner Routine raus muss und damit sicherstellen will, das, egal, was später noch in 'ner Routine implementiert wurde, die Routine beendet wird. Aber in 'ner If-else-if-Kasskade mit Exit auszusteigen, obwohl die Logik so implemtiert ist, dass das Exit nicht erforderlich ist, find' ich persönlich eher befremdlich.
Delphi-Quellcode:
Und:
function Test : Integer;
begin if a then begin Exit(1); end else if b then begin Exit(2); end else ... if z then begin Exit(26); end; // Jahre später wird in der Routine eine Änderung nötig, z. B. sowas: if (Result > 20) and (Result < 23) then begin // Mit Exit haben wir nun ein Problem, vor allem dann, wenn es nicht so offensichtlich ist, wie hier im Beispiel. // Mit der Nutzung von Result wäre es aber kein Problem. end; end; Wenn man Code nur intuitiv betrachtet und daraus Schlüsse zieht, kann man schonmal deutlich schiefliegen. Da ziehe ich die grundsätzliche Auswertung des Quelltextes doch vor. Oder das ganze mal mit Case:
Delphi-Quellcode:
statt:
function Test(i : Integer) : Integer
begin case i of 1 : Exit(1); 2.. 10 : Exit(2); 11..100 : Exit(3); else Exit(42); end; end;
Delphi-Quellcode:
Geht beides, Variante 2 ist mir da aber deutlich lieber.
function Test(i : Integer) : Integer
begin case i of 1 : Result := 1; 2.. 10 : Result := 2; 11..100 : Result := 3; else Result := 42; end; end; |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
"Logisch" sind ELSE eigentlich passend,
auch wenn beim EXIT das ELSE unnötig wäre. Wenn man aber mit ELSE und nur Result:= arbeitet, dann hat man z.B. die Chance ans Ende "einen" Haltepunkt zu setzen oder eine Loggingfunktion dort einzufügen, was bei den Exits (zentral) nicht ginge. Was ich heute in der Hilfe vom VBScript sah .... im Delphi braucht man zum Glück nicht mehr
Delphi-Quellcode:
und kann fehlerunanfäliger mit Result arbeiten. (sogar lesend)
Funktionsname := ...;
|
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
der Function. Dort kannst du doch den Haltepunkt setzen.
end
|
AW: Verständnisfrage zu Exit
Nicht immer.
Keine lokalen Variablen und Dergleichen und schon kann Exit auch direkt rausspringen. |
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
function MyFunc(Value: Integer): Integer;
begin if Value = 1 then Exit(1); if Value = 2 then Exit(2); end; |
AW: Verständnisfrage zu Exit
Irgendwie habe ich den Eindruck, dass bisher im Thread die eigentliche "Gefahr" von Exit, mit oder ohne Return-Wert komplett übersehen wurde: Exit ist im Grunde nichts anderes als ein "goto" mit einem Label direkt vorm Methodenende. Exit begünstigt schlicht Spaghetti-Code, und erlaubt das Verlassen von Methoden/Funktionen/Prozeduren an Stellen, an denen es die sonstigen Kontrollstrukturen nicht offensichtlich erahnen lassen. Es ist einfach ein Wartbarkeits- bzw. Lesbarkeitsproblem, kein technisches oder logisches.
Ich persönlich nutze es nur gelegentlich, und dann auch nur gesammelt in den allerersten Zeilen einer Methode, wo ich gelegentlich abprüfe ob alle Bedingungen zur weiteren Verarbeitung der Methode gegeben sind. Und auch das meist nur in Legacy-Codes, wo eine wirklich "saubere" Lösung sehr unwirtschaftliche größere Restrukturierungen bedeuten würden. Und ich fühle mich schmutzig dabei. Eine weitere Ausnahme sind Mini-Prozeduren, die aus maximal 10-15 Zeilen bestehen, die nur sehr kleine Aufgaben übernehmen. In diesen ist wenig genug Code, dass ein Exit nicht so leicht im allgemeinen Gewimmel untergeht, und gelegentlich zu weniger verschachteltem und besser lesbarem Code als die sonst nötigen Strukturen führt. Rein technisch gesehen wäre es in 100% der Fälle vermeidbar; diese DIskussionen sind meiner Meinung nach hinfällig. |
AW: Verständnisfrage zu Exit
:thumb:
Exit ist für mich im Großen und Ganzen ein Zeichen von unstrukturierter Programmierung, aber sicher kein empfehlenswerter Programmierstil. Les- und Wartbarkeit leiden, für meine Begriffe, extrem. |
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
oder
If Dateiname = ''
Delphi-Quellcode:
da geht man einfach raus und das ist gut so. Auch ein GoTo ist nicht in 100% der Fälle schlecht, sondern nur in 99%, und in diesem einen Prozent macht es den Code besser und nicht schlechter, egal was der Pfarrer sagt. Zum Beispiel, wenn man aus verschachtelten Schleifen herausspringt, wenn ein bestimmtes Ergebnis auf kompliziertem Weg gefunden wurde. Kein Mensch kann mir erzählen, dass es einen gestandenen Programmierer in Verwirrung stürzt, wenn am Ende einer Schleife ein Label
If not TFile.Exists(Dateiname)
Delphi-Quellcode:
oder
Weiter:
Delphi-Quellcode:
oder
Nächster Durchlauf:
Delphi-Quellcode:
steht. Es sind eher die Verrenkungen, die man betreibt, um zu beweisen, dass es auch mit der ganz ganz reinen Lehre geht, die den Code schlechter machen. Mein ich aus meiner bescheidenen Amateursicht.
MachsNochEinmalSam:
Wenn man hier schon der Hohepriesterei der Lesbarkeit und Übersichtlichkeit huldigt, warum hält dann die ganze Delphizunft an diesem unsäglichen
Delphi-Quellcode:
fest?
If Bedingung1 then
begin Mach1; end else if Bedingung2 then begin Mach2; end else begin MachNix; end; Man vergleiche das mit
Delphi-Quellcode:
Kein Mensch, wirklich keiner, würde auf die Idee kommen, das anders zu machen, wenn man nicht in eine Zunft reinkäme, die nunmal darauf geeicht ist.
If Bedingung1 then begin
exit; end else if Bedingung2 then begin Mach2; end else if Bedingung3 then begin Mach3; end else begin ... end; Mit Genugtuung sehe ich immer, dass ausgerechnet David Heffernan es auch auf die zweite Weise macht, und hier gilt das für Thomas Müller (dummzeuch) ebenso. Heffernan geht so weit, dass er überhaupt kein einfaches "then" mehr benutzt, sondern ausschließlich "then begin". Jetzt ist nicht alles richtig, nur weil David Heffernan es so macht, aber offensichtlich kann man auch so lesbaren und guten Code schreiben. Jedenfalls warte ich noch auf den Tag, an dem einer aufsteht und David mal Bescheid sagt. Ich finde die Methode 2 weder böses GoTo noch Spaghetticode oder sonstwas, sondern nur eins: Sehr übersichtlich. Es spielt - in meinen Augen - überhaupt keine Rolle, dass das "end else" nach dem "exit" technisch nicht notwendig ist: Na und? Man sieht auf einen Blick: Es gibt da 3 oder 5 oder auch 8 Zustände, die zu 3 oder 5 oder 8 Reaktionen führen, einer oder meinetwegen auch 3 oder 7 davon bedeuten "exit". "Exit" ist eine völlig legitime Konsequenz, was daran schlecht oder gar schmutzig sein soll, erschließt sich mir nicht so ganz. Jetzt habe ich mich ein bisschen ereifert, da bitte ich um Nachsicht. |
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
zudem würde ich solche Verschachtelungen gar nicht verwenden sondern direkt mit Case arbeiten.
If Bedingung1 then
exit else if Bedingung2 then Mache2 else if Bedingung3 then Mach3 else ...
Delphi-Quellcode:
case Bedingung of
1: exit; 2: Mache2; 3: Mache3; else was auch immer end; |
AW: Verständnisfrage zu Exit
Zitat:
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
Zitat:
Zitat:
|
AW: Verständnisfrage zu Exit
Juchu, lasst uns noch eine Diskussion um Goto und Goto-ähnliche Konstrukte führen! Das hatten wir schon lange nicht mehr. ;-)
Meine Meinung: Im Gegensatz zu Continue, Break und einem Goto, ist Exit ein relativ harmloses Konstrukt und hat definitiv seine Anwendung. Insbesondere verwende ich es gern, um am Anfang einer Methode die Eingangs-Voraussetzungen (Parameter, Zustand des Objekts) zu prüfen und die Methode dann zu verlassen, wenn es nichts zu tun gibt.
Delphi-Quellcode:
oder
procedure bla(const _s: string);
begin if _s = '' then begin // ein leerer String braucht nicht verarbetet zu werden. Exit; //==> end; // irgendwas längeres mit _s machen end;
Delphi-Quellcode:
Dieses "Early Return" wird durchaus häufig verwendet, ist aber nicht ganz umstritten.
procedure TSomeObject.SetVisibiel(_Value: boolean);
begin if _Value = FVisible then begin // keine Änderung -> raus Exit; //==> end; FVisible := _Value; // jetzt noch alles mögliche andere machen end; Dann gibt es noch eine andere praktische Verwendung von Exit: Das frühzeitige Verlassen von Schleifen:
Delphi-Quellcode:
Natürlich könnte man da auch Break verwenden, aber die Erfahrung hat mich gelehrt, dass ein Break gerne mal nicht die Schleife beendet, von der man denkt, dass sie beendet wird. Nachdem ich zum x-ten Mal irgendo eine geschachtelte Schleife eingebaut hatte und Break dann plötzlich nur noch diese innere Schleife verlasen hat, habe ich mir komplett abgweöhnt, es zu verwenden. Dito Continue.
function FindMatchingString(_sl: TStringList; const _s: string; out _Idx: Integer): boolean;
var i: Integer; begin for i := 0 to _sl.Count -1 do begin if StartsText(_s, _sl[i]) then begin _Idx := i; Result := True; Exit; //==> end; end; Result := False; end; Ach ja, und dann gibt es da immernoch das einzige Goto in unserer Codebase, das ich vor 13 Jahren eingebaut habe und jetzt schon aus Trotz drin lassen werde. ;-) |
AW: Verständnisfrage zu Exit
Zitat:
Dennoch finde ich GERADE hier Exit sau gefährlich! Da muss nur einer mal auf die Idee kommen, noch Code hinter die Schleife zu packen, der auf jeden Fall durchlaufen werden soll. Continue und Break haben sich bei mir bisher immer brav verhalten. Was unheimlich hilft dabei, ist es die Schleifenrümpfe brav alle in begin..end Blöcke zu verpacken, sodass der Scope immer eindeutig ist - auch optisch. |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
Delphi-Quellcode:
procedure bla(const _s: string);
begin if _s <> '' then begin // irgendwas längeres mit _s machen end; end; |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Warum das denn?
|
AW: Verständnisfrage zu Exit
Zitat:
Es kommt doch immer auf den Einzelfall an. Darüber hinaus spielen dann auch noch persönliche Vorlieben oder Vorgaben in einer Firma hinein. Darüber zu streiten macht keinen Sinn. |
AW: Verständnisfrage zu Exit
Zitat:
![]() |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
Tralla li tralla la, tralla hopsassa :stupid: |
AW: Verständnisfrage zu Exit
Zitat:
Result als lokale Variable: - Ja, da wo es Sinn macht Exit als Vorbedingung - Ja, wenn es zig Verschachtelungen vermeidet ... ... ... Habe ich theroretische Philosophieprobleme damit ? Nein, wenn ich weiss was ich da tue. Ausserdem versuche ich es möglichst gut visuell zu dokumentieren:
Delphi-Quellcode:
begin
if VorbedingungFails then begin Exit; //<== Leave here ============================================== end; ... end; |
AW: Verständnisfrage zu Exit
Zu "Exit ist genauso böse wie goto" - sehe ich nicht so - Exit hat ein unverrückbares Ziel: das Ende der Routine, wohingegen zu einem goto immer ein label gehört, was sonstwo sein kann.
Zu "Result erst so spät wie möglich setzen" - ja, das verhindert, dass der Compiler den Wert für eine Weile merken und zwischenspeichern muss, entweder auf dem Stack oder er blockiert ein Register, was dann woanders fehlt. Aber wenn man bei dieser Argumentation ist, dann muss man noch ganz viele andere Dinge beachten und sich fragen, ob man das dann macht, wenn man genau weiß warum oder einfach nur "cargo cult" folgt. Zu "Exit benutzen oder nicht" - teilweise Geschmackssache, ich nutze gern ein Exit aus einer "suche mir ein Element"-Schleife und handhabe den "kein Fund"-Fall einfach nach der Schleife. Oder ich verabschiede mich nach einigen anfänglichen negativ formulierten Überprüfungen gleich mit einem Exit, so dass ich den ganzen eigentlichen Code nicht unterhalb der positiv formulierten Bedingung in einem Block habe (sofern nicht absolut optimiert, denn da gelten wieder andere Regeln - Stichwort branchless programming bzw common path ohne conditional jump taken). Eine Sache noch zu Exit oder nicht - die Benutzung von Exit kann durchaus dafür sorgen, dass der Compiler auch tatsächlich an dieser Stelle ein ret einbaut wohingegen der Fall mit einem else... ein jmp an das end der Routine erfolgt. |
AW: Verständnisfrage zu Exit
Hallo,
auch ich benutze Exit bei numerischen Berechnungen recht oft, häufig in folgender beispielhafter Weise:
Delphi-Quellcode:
Ich habe damit gute Erfahrungen gemacht.
Function Komplizierte_Berechnung(CONST a, b, c: Extended;
CONST X_Vektor, Y_Vektor, Z_Vektor: TExtended_Array; VAR A_Matrix: TExtended_Matrix; VAR f, g, h: Extended): Integer; VAR Diverse dynamische Strukturen; Begin Dynamische Strukturen initialisieren; . . . Try IF NOT Check_1(...) Then Begin Exit(ErrorCode_1); End; IF NOT Check_2(...) Then Begin Exit(ErrorCode_2); End; . . . IF Bedingung_1 Then Begin Berechnungen_1; Exit(ErrorCode_3); End; IF Bedingung_2 Then Begin Berechnungen_2; Exit(ErrorCode_4); End; . . . Finally Rückgabeparameter schreiben; Dynamische Strukturen freigeben; End; End; Gruß, Andreas |
AW: Verständnisfrage zu Exit
Zitat:
|
AW: Verständnisfrage zu Exit
Zitat:
Empfinde es schlecht hässlich, wenn man sinnlos eine weitere Variable benutzt, anstatt direkt Result. Und von der Preformance her ist das kein Unterschied. Es kann sogar sein, dass die zusätzliche Variable mehr speicher benötgt, wenn es für den Compiler nicht möglich ist, die Resultvariable (deren Speicherplatz) erst ab der Stelle der Zuweisung zu reservieren. Es gibt aber Einwas, wo man das als Nachteil betrachten könnte. Denn z.B. ein Result als Interface oder String, wird vom Compiler als VAR-Parameter behandelt. Kommt es dann zu einer Exception, dann würde die äußere Variable (da wo das Result der Funktion zugewiesen werden sollte) bereits verändert sein, was man so nicht direkt erwarten würde.
Delphi-Quellcode:
Das selbe Beispiel mit Integer als Variable/Result, da bleibt es "1", da an "X" ja noch nchts zugewiesen wurde, weil es "vorher" abgeraucht ist.
function MyFunc: string;
begin Result := '2'; raise Exception.Create(''); end; procedure Test; var X: string; begin X := '1'; try X := MyFunc; except ShowMessage(X); end; end; Für mich sind nach einer Exception Results von jeglichen Funktionen sowieso als "ungültig" anzusehen, somit gibt es IMHO damit eigentlich auch keine Probleme. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz