Ian Branch 127 Posted January 25, 2021 Hi Team, I suspect I have been doing something wrong. And not for the first time. ;-) If I have the following construct.. try ..... .... if x then begin ..... Exit; end else begin .... ... end; Finally FreeAndNil(something); end; Will the Exit bypass the FreeAndNil?? I suspect it does and I may have been causing myself some grief. Regards & TIA, Ian Share this post Link to post
Guest Posted January 25, 2021 (edited) 1 hour ago, Ian Branch said: Hi Team, I suspect I have been doing something wrong. And not for the first time. 😉 If I have the following construct.. you can try some like this: implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); var stMyList : TStringList; bMyCondition: boolean; begin try bMyCondition := true; // test on "false" // if bMyCondition then exit; // // only create this instance if condition is "false", then, not use more memory allocation // if necessary, it's possible put a "Try Except" for avoid any exceptions" and memory leaks here or // create the instance before 1º "try", and, use last "finally" to release it stMyList := TStringList.Create; try // stMyList.Add('new value'); // finally FreeAndNil(stMyList); end; finally ShowMessage('im here...'); end; end; initialization ReportMemoryLeaksOnShutdown := true; finalization end. if you need test your conditinal later create the instance: procedure TForm1.Button1Click(Sender: TObject); var stMyList : TStringList; bMyCondition: boolean; begin try bMyCondition := true; // stMyList := TStringList.Create; try if bMyCondition then exit; // stMyList.Add('new value'); // finally FreeAndNil(stMyList); ShowMessage('im here...2'); end; finally ShowMessage('im here...1'); end; end; hug Edited January 25, 2021 by Guest Share this post Link to post
David Heffernan 2345 Posted January 25, 2021 1 hour ago, Ian Branch said: Will the Exit bypass the FreeAndNil? No. This is of course easy to test using debugging techniques, trace logging etc. It's also documented in the language guide. Share this post Link to post
Remy Lebeau 1392 Posted January 25, 2021 2 hours ago, Ian Branch said: Will the Exit bypass the FreeAndNil?? No, see: http://docwiki.embarcadero.com/RADStudio/en/Exceptions_(Delphi)#Try...finally_Statements Quote The try...finally statement executes the statements in statementList1 (the try clause). If statementList1 finishes without raising exceptions, statementList2 (the finally clause) is executed. If an exception is raised during execution of statementList1, control is transferred to statementList2; once statementList2 finishes executing, the exception is re-raised. If a call to the Exit, Break, or Continue procedure causes control to leave statementList1, statementList2 is automatically executed. Thus the finally clause is always executed, regardless of how the try clause terminates. Share this post Link to post
Fr0sT.Brutal 900 Posted January 26, 2021 9 hours ago, Ian Branch said: Will the Exit bypass the FreeAndNil?? I suspect it does and I may have been causing myself some grief. Ehm... you could have checked it by yourself in 5 secs. Instead you wasted much more time for writing the post and other guys wasted time for answering. Where's the logic?)) Share this post Link to post
Ian Branch 127 Posted January 26, 2021 To All, Regrettably my skills & knowledge are not at your depth. If they were, then I wouldn't have needed to ask the question. I have also always been a believer that if you have a question in your mind then someone else probably has too. Ergo, ask it, and get the answer and at the same time make the answer available to others. In this particular case, I looked at Exit but not at Try-Finally. Why, I don't know, it simply didn't occur to me. I'm going to call it a Senior's Moment. My thanks to those that have responded and clarified the issue for me and I unreservedly apologise to all inconvenienced by responding to my question. I will attempt to do better next time. Ian 2 Share this post Link to post
Guest Posted January 26, 2021 hi @Ian Branch the forum is public and ANYONE IS NOT OBLIGATED LOST YOUR TIME! ask US always that you need, and, if anyone have some time to explain ok! if not, ok too! hug Share this post Link to post
balabuev 102 Posted January 26, 2021 try Exit; // Works. "Finally" code will be executed. finally Exit; // Compile error; but, will work in try/except. end; // ========== for i := 0 to 10 do begin try Break; // Works. "Finally" code will be executed. Continue; // finally Break; // Compile error; but, will work in try/except. Continue; // end; end; // ========== goto L1; // Compile error. goto L2; // try L1: finally L2: end; // ========== try goto L1; // Compile error. goto L2; // finally goto L1; // Compile error. goto L2; // end; L1: L2: // ========== try L2: goto L1; // Compile error. finally L1: goto L2; // Compile error. end; The above is just to summarize different kinds of jumps 4 Share this post Link to post
balabuev 102 Posted November 16, 2023 (edited) This one is interesting: try goto L1; // Compile error, but why? finally end; L1: Exit, Break and Continue work in the above case. Edited November 16, 2023 by balabuev Share this post Link to post
dummzeuch 1505 Posted November 16, 2023 1 hour ago, balabuev said: This one is interesting: try goto L1; // Compile error, but why? goto L2; // finally end; L1: L2: Exit, Break and Continue work in the above case. What would you want this code to do? directly jump to the label - or - execute finally and then jump to the label ? Neither really makes sense to me. Exit, Break and Continue always execute finally. Share this post Link to post
Kas Ob. 121 Posted November 16, 2023 1 hour ago, balabuev said: Compile error, but why? Well, try..finally block inside the try..finally..end will construct special frame to be handled only by its finally..end block, hence goto L1 will not be simple as what it should do, and it must become : goto L1 -> finnaly...end block -> label L1: though it is doable and the compiler simply does not implement it. Share this post Link to post
balabuev 102 Posted November 16, 2023 3 minutes ago, dummzeuch said: What would you want this code to do? Same thing, Exit, Break and Continue do, of course, - execute finally(ies) and jump out. Share this post Link to post
balabuev 102 Posted November 16, 2023 Just now, Kas Ob. said: hough it is doable and the compiler simply does not implement it While compler implements it for Exit, Break and Continue. Share this post Link to post
Kas Ob. 121 Posted November 16, 2023 1 hour ago, balabuev said: While compler implements it for Exit, Break and Continue. Right, but lets see exactly what is going under the hood Exit, will not care about any variables and will clean them for the whole procedure. Break and Continue the compiler have a clear view of what should keep what not, GoTo, will make a mess and hide some dangerous behavior and i doubt Delphi compiler will be able to handle it, even it did, the use cases is near zero. Away from that there is critical differences between try..except and try..finally, with except there is a trap for exception, the finally..end block will only be executed on an exception, that known, but what about the generated code, the compiler will not give a rat ass about any logic inside that block or after it, it is your problem (the programmer), with finally..end the block must be executed every time even when an exception is raised, here the compiler is responsible to greater degree with the logic flow, again with goto inside try..finally i think the compiler can be made to handle it, but as i prefer : if it can't be build to do it right, then don't start with it or don't accept such code. Share this post Link to post
David Heffernan 2345 Posted November 16, 2023 (edited) 4 hours ago, balabuev said: This one is interesting: try goto L1; // Compile error, but why? goto L2; // finally end; L1: L2: Exit, Break and Continue work in the above case. For the sake of future readers, this example is not minimal. I can't imagine where there are two goto statements. The issue you raise needs one. Minimality is important. This is the example you should have posted: procedure Foo; label L1; begin try goto L1; finally end; L1:// E2127 here end; The other thing that is missing is what the compiler error says. Often there's information there. Why omit it. Again for future readers, it says: Quote [dcc32 Error] E2127 'GOTO L1' leads into or out of TRY statement, FOR-IN statement whose enumerator has destructor, or a block containing local variable Edited November 16, 2023 by David Heffernan 1 Share this post Link to post
balabuev 102 Posted November 16, 2023 13 minutes ago, David Heffernan said: For the sake of future readers, this example is not minimal. Yes, my fail. Should be: try goto L1; // Compile error, but why? finally end; L1: 1 hour ago, Kas Ob. said: GoTo, will make a mess and hide some dangerous behavior and i doubt Delphi compiler will be able to handle it Not more mess than Break, Continue or usual "goto". Share this post Link to post
David Heffernan 2345 Posted November 16, 2023 2 hours ago, balabuev said: Yes, my fail. Should be: try goto L1; // Compile error, but why? finally end; L1: Actually that's not where the compiler reports the error. The compiler reports the error as indicated in my post. At the label. Share this post Link to post
balabuev 102 Posted November 16, 2023 3 minutes ago, David Heffernan said: Actually that's not where the compiler reports the error Not a big deal. Actually, even worse for a compiler 🙂 Share this post Link to post
Pat Foley 51 Posted November 16, 2023 The try...finally...end is typically used to free memory. This sample simply sets the count back to zero and has a counter for number of count resets in the finally. Goto's and try's don't mix. var Count: 0..100 = 0; Reentrant: 0..100 = 0; procedure TForm1.Button2Click(Sender: TObject); begin //Constraint If Count > 4 then exit; (Sender as TButton).Enabled := False; Inc(Count); Caption := 'Goingto ' + Count.ToString; Sleep(100); Try Caption := Format('Goneto %d',[Count]); If Count < 9 then begin Sleep(110); Button2Click(Sender); //Poor Person's ProcessMessages end; finally Inc(Reentrant); Count := 0; sleep(12_00); Caption := Format('Please !gotos!* use %d jumps',[Reentrant]); End; //* pram notation Beattie //Enables first finally pass :( (Sender as TButton).Enabled := True; end; Share this post Link to post
David Heffernan 2345 Posted November 16, 2023 6 hours ago, balabuev said: Actually, even worse for a compiler Well, you say that, but it's the placement of the label that determines whether this an error or not so I think that's fine. Share this post Link to post
balabuev 102 Posted November 17, 2023 9 hours ago, David Heffernan said: Well, you say that, but it's the placement of the label that determines whether this an error or not so I think that's fine. No doubt that eror placement is not good too, since the message itself is about specific goto statement, not about the label generally. But, it's not matter. What is matter - the error itself. They implemented actually the same under-the-hood functionality for Break/Continue, but ignored goto. Because, who need it, right? Share this post Link to post
Dalija Prasnikar 1396 Posted November 17, 2023 8 minutes ago, balabuev said: They implemented actually the same under-the-hood functionality for Break/Continue, No, it is not the same functionality. Break and Continue will just make single unconditional jump to the finally, while goto would require two jumps, one of them conditional. It is far from being the same. Share this post Link to post
dummzeuch 1505 Posted November 17, 2023 21 minutes ago, Dalija Prasnikar said: No, it is not the same functionality. Break and Continue will just make single unconditional jump to the finally, while goto would require two jumps, one of them conditional. It is far from being the same. No. Both, break and continue make a jump to the finally block and then to the end or beginning of the loop. Not a big difference to what a goto must do. The only difference is that goto can jump to an arbitrary position in the code while break and continue only jump to the end or beginning of a loop. 1 Share this post Link to post
balabuev 102 Posted November 17, 2023 (edited) 3 hours ago, Dalija Prasnikar said: while goto would require two jumps, one of them conditional I cannot imagine, where the difference come from. Moreover, handling finally is a "call", not jump. So, what Break do, is a single "call" to handle each exiting try/finally, and then - usual jump. So, goto should do the same. Edited November 17, 2023 by balabuev Share this post Link to post
Dalija Prasnikar 1396 Posted November 17, 2023 2 hours ago, dummzeuch said: No. Both, break and continue make a jump to the finally block and then to the end or beginning of the loop. Not a big difference to what a goto must do. The only difference is that goto can jump to an arbitrary position in the code while break and continue only jump to the end or beginning of a loop. You are right, I forgot that there could be code in the loop after the finally, which requires additional jump. Share this post Link to post