Jump to content
Ian Branch

Try-Finally-end; & Exit??

Recommended Posts

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
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 by Guest

Share this post


Link to post
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
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
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

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

  • Like 2

Share this post


Link to post
Guest

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
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 :classic_biggrin:

 

  • Like 4

Share this post


Link to post

This one is interesting:

try
  goto L1; // Compile error, but why?
finally
end;

L1:

Exit, Break and Continue work in the above case.

Edited by balabuev

Share this post


Link to post
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
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
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
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
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
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

 

Edited by David Heffernan
  • Like 1

Share this post


Link to post
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
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
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

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
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
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
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
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.

  • Like 1

Share this post


Link to post
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.

 

image.thumb.png.304ef3c2cddb902812f34cb6ca0b9151.png

 

So, goto should do the same.

 

 

Edited by balabuev

Share this post


Link to post
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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×