![]() |
Delphi-Version: 5
"FinalllyExit" gewünscht
Ich würde mir folgende Delphi-Syntax wünschen:
Delphi-Quellcode:
function MyFunc(var Counter: Integer): Real;
var O: TMyObject; begin O := TMyObject.Create; O.MachWas(Counter); if (O.Dies) then Exit(Random) else if (O.Das) then Exit(0); Result := 1 / 0; // Exception FinallyExit: // <-- Vor dem Aussprung IMMER ausführen, was folgt FreeAndNil(O); Inc(Counter); end; Es geht mir hier nur darum, dass vor dem Aussprung aus der Funktion IMMER noch irgend etwas erledigt wird. FinallyExit könnte also ein automatisches GoTo-Label implemententieren, so dass auch Exit dort hin führt. Ebenso könnte dieses Konstrukt als Try-Finally-Block fungieren. Um das zu erzielende Ergebnis umzusetzen, müsste man bisher einen Try-Finally-Block definieren und die Exit-Anweisungen durch GoTo ersetzen, wobei hier zuvor noch Result zugewiesen werden müsste. Ich habe mir eine solche Syntax schon öfters gewünscht. Was haltet Ihr davon? |
AW: "FinalllyExit" gewünscht
Schonmal ausprobiert?
exit springt innerhalb eines try-finally-Blocks in den finally-Block ;) |
AW: "FinalllyExit" gewünscht
Überflüssig.
Exakt diese Funktionalität wird bereits durch try-finally abgedeckt. Falls du das nicht glaubst, zeige bitte ein Stück Code wo das finally nicht ausgeführt wird ;) |
AW: "FinalllyExit" gewünscht
Ok danke. Klar glaube ich Euch das, aber ich wusste das nicht.
Ich arbeite selten mit try-Blöcken. Ich hatte beim programmieren lernen gelesen, dass man try-Blöcke (nur) verwendet, um Fehlermeldungen bei erwarteten (und zu tolerierenden) Fehlern zu unterdrücken. Also z.B. bei I/O-Funktionen. Das steckt halt so drin. Aber ich werde mir das noch mal genauer ansehen... Danke! |
AW: "FinalllyExit" gewünscht
Try-Except = auf Fehler (Exceptions) reagieren ... fast so, wie du es gelernt hast
Try-Finally = immer einen bestimmten AufräumCode ausführen, egal was passiert Aber nicht "unterdrücken", sondern behandeln. :warn: |
AW: "FinalllyExit" gewünscht
Eine wichtige und immer wiederkehrende Funktion von try Blöcken ist neben dem Behandeln von Exceptions auch beispielsweise das sichere Freigeben von Resourcen:
Delphi-Quellcode:
MyObject := TObject.Create;
try MyObject.DoSomething; finally MyObject.Free; end; |
AW: "FinalllyExit" gewünscht
Na ja, grundsätzlich sind mir die Fehlerbehandlungen schon klar.
Nur, wenn es irgendwo knallt, ist es m.E. zweitrangig, ein erzeugtes Objekt auch wieder frei zu geben. Jedenfalls nicht, wenn nicht innerhalb der Fehlerbehandlung selbst wieder ein konstistenter Projektzustand hergestellt wird. Wenn Exit in einem Try-Block in finally springt, ist das schon mal eine Lösung, aber nicht wirklich das, was ich erwartet habe. Mal ein Beispiel (ungetestet, nur Resultat Eurer Erklärungen):
Delphi-Quellcode:
function MyFunc: Real;
var O: TMyObject; begin O := TMyObject.Create; try O.DoA; if O.A then Exit(-1); // ist kein Exit sondern springt in finally - DoNotIfExitBefore wird noch bearbeitet, das wäre ohne Try-Block nicht der Fall, da würde die Funktion VERLASSEN O.DoB; Result := 1 / 0; // Exception -> Sprung nach finally O.DoC; Result := O.Result; finally O.Free; end; DoNotIfExitBefore; // wird trotz EXIT ausgeführt end; Nach Eurer Beschreibung reagiert Exit nicht mehr "normal", wenn man es (z.B. nachträglich) in einen Try-Block kapselt. Zumindest muss man darauf wohl unbedingt achten, da Exit dann nicht wirklich die Funktion verlässt. Manchmal möchte man ja eine Funktion unter bestimmten Bedingungen gar nicht ausführen. Wenn man dann das Exit in ein Try-Block aufnimmt, nach dessem finally-end noch etwas ausgeführt wird, dann funktioniert das Exit nicht erwartungsgemäß. Und zur Objektfreigabe: Wenn im obigen Fall O.DoC nicht mehr ausgeführt wird und man den Fehler nachträglich nicht (durch eine Neuberechnung o.ä. korrigiert) bringt einen die Objektfreigabe auch nicht wirklich weiter. Das Projekt arbeitet fehlerhaft bzw. nicht zuverlässig. Der Fehler muss UNBEDINGT bereinigt werden, aber die Freigabe des Objektes finde ich im Fehlerfall mindestens nachranging. Ob das Objekt nun aufgelöst wird oder nicht - das Programm beinhaltet fehlerhafte Daten. Die Funktion muss angepasst werden und eine "drohende" Division durch Null selbständig behandeln. Aber ich schaue mir die ganze Try-Geschichte natürlich nochmal an. |
AW: "FinalllyExit" gewünscht
Zur not könntest du dich mit einer Hilfsvariable, die du sagen wir nach dem Exit Befehl auf true setzt aus der Afäre ziehen. Dann checkst du nach dem finally, ob die Variable gesetzt ist und führst nur dann eventuelle weitere Funktionen aus. Guter Stil ist das denke ich allerdings nicht ..
|
AW: "FinalllyExit" gewünscht
Zitat:
Exit springt aus der Prozedur, aber vorher werden noch die Finally-Abschnitte der umgebenden Try-Finally abgearbeitet. Bei Try-Except wird, wenn in dem Except-Teil keine neue Exceptions ausgelöst oder die alte Exception weitergeeicht wird, der nachfolgende Code ausgeführt, da die Exception ja abgefangen wurde. Zitat:
Dieses kann aber auch bedeuten, daß man noch schnell eine ordentliche Fehlermeldung ausgibt und dann das Programm gezielt und ordnungsgemäß beendet. |
AW: "FinalllyExit" gewünscht
Ok, das (finally und DANN exit) hört sich sehr gut an. Ich schaue mir das wie gesagt noch genau an.
Danke! PS: In meinem Beispiel ist natürlich klar, dass O vor dem Exit freizugeben wäre. Da war ich etwas zu hektisch. Sorry. |
AW: "FinalllyExit" gewünscht
Zitat:
Ein Speicherleck ist zwar nicht schön aber RAM ist meistens genug da. Wenn andere Ressourcen nicht freigegeben werden, kann es schon ärgerlicher werden. Und genau dafür hat man ja try-finally ;) |
AW: "FinalllyExit" gewünscht
Zitat:
DoNotIfExitBefore |
AW: "FinalllyExit" gewünscht
Mag nur meine Meinung, aber für jedes Exit sollte es einen Schlag in den Nacken geben.
Klar, an manchen Stellen kann man sich in etwas vertrackten Konstrukten einfach aus der Affaire ziehen, aber sauber gecoded ist es zu 99.99% vermeidbar. |
AW: "FinalllyExit" gewünscht
@Stevie: Danke, genau diese Worte habe ich mir beim Lesen dieses Themas gewünscht :thumb:
|
AW: "FinalllyExit" gewünscht
Zitat:
Ein Beispiel:
Delphi-Quellcode:
// mit Exit
begin if not FileExists(Filename) then Exit; LoadFile(); ProcessFile(); DoSomethingElseWithFile(); end; // ohne Exit begin if FileExists(Filename) then begin // extra Zeile // + Verschachtelung LoadFile(); ProcessFile(); DoSomethingElseWithFile(); end; // extra Zeile |
AW: "FinalllyExit" gewünscht
Zitat:
Zumal man mit Exit(Value) in Funktionen auch gleich einen Result-Wert zuweisen kann. |
AW: "FinalllyExit" gewünscht
Grade wenn man viele APIs hintereinander aufruft und immer wieder die Rückgabe prüft, dann hat man ohne Exit spätestens nach der 4.-5. Verschachteltung viel Spaß den Code sauber einzurücken :D
|
AW: "FinalllyExit" gewünscht
Ist die überladene Funktion Exit mit Value neu?
Weil hier bei mir gibts die nicht, ich hab nur ein Exit()! |
AW: "FinalllyExit" gewünscht
Zitat:
Ernsthaft - um 2 Codezeilen zu sparen? Worin leidet denn beim 2. die Lesbarkeit? Stell dir vor, man baut mal sowas wie Logging ein:
Delphi-Quellcode:
Ah, dann kommt bestimmt die Frage, wie man mit trotz Exit noch bestimmten Code ausführen kann... Merkste was?
begin
Logger.EnterMethod('LoadFile'); if not FileExists(Filename) then Exit; LoadFile(); ProcessFile(); DoSomethingElseWithFile(); Logger.LeaveMethod('LoadFile'); end; begin Logger.EnterMethod('LoadFile'); if FileExists(Filename) then begin LoadFile(); ProcessFile(); DoSomethingElseWithFile(); end; Logger.LeaveMethod('LoadFile'); end; Zitat:
Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Danke. |
AW: "FinalllyExit" gewünscht
Ja.
Ich glaub seit 2010/2009. Wie gesagt, ich fordere ja schon lange und nicht umsonst eine Kennzeichnung in der OH, seit wann es was gibt, so wie man es z.B. aus dem MSDN kennt. |
AW: "FinalllyExit" gewünscht
Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Wenn ein EXIT unsauber wäre, dann gilt das auch für Exceptions. Auch verstehe ich nicht, wieso es in allen modernen Programmiersprachen so ein Konstrukt gibt. Wenn das unsauber oder veraltet wäre, würde man das doch wegkürzen, so wie Goto's. "Exit" ist so gut wie immer sauberer, als aus einer verschachtelten Schleife mit Hilfvariablen à la "AbortedFlag" herauszutorkeln. "Vermeidbar" ist es natürlich immer, aber das sind Schleifen auch: Wozu gibt es schließlich (Rechts-)Rekursion :stupid: Was ist hier wohl übersichtlicher?
Delphi-Quellcode:
Allerdings würde ich das "FileExists"-Beispiel auch so wie Stevie codieren.
For i:=1 to N Do
For j := 1 to M Do Begin If Bla[i,j].HasInvalidData() Then Exit; Bla[i,j].Process(); ... End; ... // ... i := 1; Aborted := False; While (i <= N) and not Aborted Do Begin j := 1; While (j <= M) and Not Aborted Do Begin If Bla[i,j].HasInvalidData() Then Aborted := True Else Begin Bla[i,j].Process(); ... Inc(J) End; End; Inc(i); End; |
AW: "FinalllyExit" gewünscht
Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Deshalb meinte ich "hier und da". Aber es gibt Fälle, in denen es andersherum viel leserlicher und besser ist, so wie von Zacherl angesprochen. Zumindest habe ich so das Gefühl. Und noch etwas: Zitat:
Sonst hast du 2*20 Extra Zeilen und ganz zu Geschweigen von der ganzen Einrückung! Edit: Zitat:
|
AW: "FinalllyExit" gewünscht
Es gibt keinen Anlass, sich im Ton zu vergreifen - erst recht nicht in der Diskussion, ob man ein Sprachkonstrukt nun verwenden solle oder nicht. Wer das dennoch tut, hat sich hier definitiv zum letzten Mal im Ton vergriffen, meine Güte nochmal. Es ist /NUR/ ein Sprachkonstrukt, vergesst das bitte nicht.
|
AW: "FinalllyExit" gewünscht
Normalerweise prüft man die Rahmenbedingungen ja bevor man einen Process startet
Delphi-Quellcode:
Was ich meine ist, das man ein Exit eigentlich leicht dadurch verhindert, dass man vorm Aufruf einer Function die Rahmenbedingungen prüft. Wenn dann bei Processing ein Fehler auftritt ist eine Exception auch ganz angemessen geantwortet. Einfach ein Exit am Function-Eingang ist ja für den Aufrufer nicht von erfolgreichem Aufruf zu unterscheiden.
begin
if FileExists(Filename) then ProcessFile(Filename) else ShowMessage('File not exists'); end; function ProcessFile(Filename); begin bla... end; Der andere Fall, ein Exit einzusetzten um Aufgabenblöcke zu überspringen, entspricht einem Goto Ende:. Mehr braucht man ja nicht zu schreiben, ausser das sowas auch durch splitten der Aufgaben pro Funktion meist eleganter gelöst wird. |
AW: "FinalllyExit" gewünscht
Zitat:
Zitat:
An alle, die jetzt Codeschnippsel produzieren, um von der Nützlichkeit und Unabdingbarkeit von Exit zu überzeugen: Hier habt ihr nen Keks. :lol: |
AW: "FinalllyExit" gewünscht
Ok, wie es nun aussieht, fällt das in die Kategorie "Geschmackssache".
Denn beides hat ihre Vorteile und Nachteile! Es gibt Fälle, in denen das eine praktischer ist, das andere weniger. Fundamentalisten werden das nun verweigern, aber so ist das nunmal! *Keks_mampf Edit: Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Dieser Schwachfug ist in Zeiten aufgekommen, als auffiel, das ein GOTO etwas furchtbar Böses ist und ein EXIT (und BREAK) ja eigentlich auch irgendwie ein GOTO bzw. ein Sprung. Und vor lauter Verteufeln hatte man doch glatt vergessen, das das soooo elegante Exceptionhandling nichts Anderes ist, als ein objektorientiertes SetJmp/LongJmp und damit eigentlich auch zu verteufeln wäre. Aber gut: Vertreter der Gattung "EXIT's sind schlechter Codestil" behaupten das ja grundsätzlich und sind daher nicht in der Lage, dies grundsätzlich zu belegen. Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Man kann Exit, Goto, With etc. so einsetzen, dass es übersichtlicher wird. Aber man kann mit den genannten Anweisungen auch Chaos in den Code bringen. Deshalb wird wohl davon abgeraten, zumal es fast immer eine Alternative gibt. Ich kenne wenig Delphi-Code, wo Exit ungünstig eingesetzt wird und ich deshalb rätseln musste wie eine Funktion arbeitet. Als ich mit C# angefangen hatte, hat mich das inflationär eingesetzte return oft viel Zeit gekostet. Bei Delphi bn ich doch immer wieder froh, dass man von Haus aus etwas strengere Regeln anlegt (auch wenn es manchmal etwas übertrieben sein mag) |
AW: "FinalllyExit" gewünscht
Zitat:
Meine Meinung zu dem Thema ist folgende (die darf ich ja noch haben und auch kund tun, oder? vielen Dank): Da in Delphi das Statement
Delphi-Quellcode:
nunmal nicht so wie in anderen Sprachen
Result := xyz;
Delphi-Quellcode:
das direkte Verlassen der Routine zur Folge hat und danach weitergarbeitet wird/werden kann, hat man mit dem Benutzen von Exit 2 verschiedene Verhaltensweisen: die "herkömmliche" (Abarbeiten der Routine bis zum Ende) und das direkte Verlassen (mit oder ohne Rückgabewert). Benutze ich die herkömmliche Weise, kann ich sicher sein, dass sich alles immernoch genauso verhält, wenn ich weiteren Code hinzufüge (z.B. Objekt freigeben, Logging Eintrag, etc). Das ist bei einem Exit nicht so. Es verändert den gewohnten Ablauf (im Sinne von 1 Eingang und 1 Ausgang), indem es einen weiteren Ausgang aus der Routine schafft.
return xyz
Ja, richtig, hier prallen wieder mal die unterschiedlichen Ansichtsweisen, was sauberer Code ist und was nicht, aufeinander. Ich stehe nach wie vor zu meiner Meinung und ich werde auch an irgendeiner Stelle wo es "nötig ist", von den 0.01% der Fälle Gebrauch machen und ein Exit einsetzen. Aber in keinem der hier im Thread erwähnten Fälle. |
AW: "FinalllyExit" gewünscht
Break und Exit haben nunmal ihre Berechtigung und auch ich nutze sie sehr oft.
Genauso wie das super GOTO wird manchmal verwendet. (ich wünsche mir auch noch ein GOSUB) Ja, wenn man ganz pervers ist, dann verwendet man auch noch Exceptions, zur Steuerung des Programmablaufs. Und Timer, sowie ProcessMessages für langanhaltende Programmteile, anstatt von Threads. So, jetzt dürft ihr mich steinigen. ich steh dazu, daß ich Exit und auch manchmal Goto verwende, vorallem wenn sich dadurch der Programmablauf vereinfachen oder übersichtlicher gestalten läßt. |
AW: "FinalllyExit" gewünscht
Pass auf, dass du nicht gesteinigt wirst. Du läufst hier die Gefahr...
Du hast es ja eh selbst schon befürchtet xD |
AW: "FinalllyExit" gewünscht
Wenn man Exit richtig einsetzt erhöht das die Lesbarkeit; wenn man es falsch einsetzt verringert man die Lesbarkeit.
Es geht also nicht um die Anzahl der Zeilen oder Optik sondern um die Lesbarkeit. Nach meiner Erfahrung gilt es dabei zu beachten: 1.) wenn man Exit verwendet, dann möglichst frühzeitig aussteigen
Delphi-Quellcode:
2.) Exit nicht verwenden, wenn man gezwungen wäre Anweisungen zu wiederholen
procedure GoodExample1(arg1,arg2,..);
begin if arg1 = arg2 then Exit; // hier folgen einige weitere Anweisungen Anweisung1; ... AnweisungN; end;
Delphi-Quellcode:
3.) Exit nur einmal verwenden
procedure BadExample2(arg1,arg2,..);
begin Machwas; if (IrgendeineBedingung) then begin MachNochIrgendwas; // doppelter Code Exit; end; // hier folgen einige weitere Anweisungen ..... MachNochIrgendwas; // doppelter Code end; Wenn man an mehreren Stellen eine Funktion/Procedure mit Exit verlässt, dann verschlechtert dies die Lesbarkeit. 4.) Exit aus einer Schleife Hier zeigt sich ganz klar der Vorteil von Exit; man kann eine Schleife und zugleich die Funktion/Procedure verlassen, ohne dass der der Schleife folgende Code ausgeführt wird. Man spart sich so die Verwendung eines boolean Flags. 5.) Exit in "Kleinfunktionen" Manchmal wird Exit verwendet, ohne wirklich eine Verbesserung der Lesbarkeit zu bringen. Das zeigt sich z.B. in Funktionen mit nur ganz wenigen Anweisungen
Delphi-Quellcode:
Dies lässt sich so umschreiben (und man spart sogar eine Zeile):
function BadExample2(arg..):Boolean;
begin result := False; if EineBedingung then Exit; // sehr unschön EineEinzigeWeitereAnweisung; Result := True; end;
Delphi-Quellcode:
Mit diesem Kochbuch kann eigentlich in Bezug auf Exit nichts mehr schiefgehen.
function GoodExample2(arg..):Boolean;
begin result := not EineBedingung; // anstatt "not" besser die Bedingung umformulieren if Result then EineEinzigeWeitereAnweisung; end; So und nun habt euch wieder lieb!! |
AW: "FinalllyExit" gewünscht
Zitat:
Das: Zitat:
Zitat:
Sicher gibt es auch genau so gute Beispiele wie man seinen Code mit Exits und Breaks verhunzen kann. Es kommt eben immer auf das richtige Maß an. Alles mit Scheuklappen auf eine vorgebene Weise zu machen ist übrigens auch ein Anti-Pattern: Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
Dazu sag ich dann nur: Zitat:
|
AW: "FinalllyExit" gewünscht
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:46 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