Recent

Author Topic: What is good in using try..finally?  (Read 21963 times)

jollytall

  • Sr. Member
  • ****
  • Posts: 320
What is good in using try..finally?
« on: October 07, 2021, 05:48:08 pm »
I read many tutorials, etc., and I understand how it works. But I still miss to see why it is a good programming practice vs. using try..except.

The classic usecase mentioned is:

Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     Screen.Cursor := crHourglass;
  4.     try
  5.       // long algorithm...
  6.     finally
  7.       Screen.Cursor := crDefault;
  8.     end;
  9.   end;

Isn't it the same as:

Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     Screen.Cursor := crHourglass;
  4.     try
  5.       // long algorithm...
  6.     except
  7.       // handle the exception or decide not to, and let it further be raised to the caller of proc a.
  8.     end;
  9.   Screen.Cursor := crDefault;
  10.   end;

My understanding is that with try..except the execution continues even if an exception is raised and either handled or even remains unhandled.
To me the second approach seems more logic, and forces the programmer to think why he put the try block and what he wants to do (or not to do) with the exception.
The only "reason" why I can imagine that someone wants to use try..finally is that he has nothing to put in except and so it is more "elegant" than an empty except, just because the language does not allow a try both without except and finally.

With the same logic, I do not see why it is recommended many places to use two try.. blocks nested. It is to bypass the fact that you cannot use try..except..finally, but what is the benefit of
Code: Pascal  [Select][+][-]
  1.     procedure a;
  2.       begin
  3.         Screen.Cursor := crHourglass;
  4.         try
  5.           try
  6.             // long algorithm...
  7.           except
  8.             // handle the exception or decide not to, and let it further be raised to the caller of proc a.
  9.           end;
  10.         finally
  11.           Screen.Cursor := crDefault;
  12.         end;
  13.       end;
over the second method shown above?


alpine

  • Hero Member
  • *****
  • Posts: 1069
Re: What is good in using try..finally?
« Reply #1 on: October 07, 2021, 06:17:50 pm »
The finally block gets always executed! In your second code snippet Screen.Cursor := crDefault; will be skipped if the exception is re-raised from the exception handler with raise or there is no suitable handler for the exception type.
« Last Edit: October 07, 2021, 06:19:39 pm by y.ivanov »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

dseligo

  • Hero Member
  • *****
  • Posts: 1222
Re: What is good in using try..finally?
« Reply #2 on: October 07, 2021, 06:28:37 pm »
The finally block gets always executed! In your second code snippet Screen.Cursor := crDefault; will be skipped if the exception is re-raised from the exception handler with raise or there is no suitable handler for the exception type.

Or if you have 'Exit' in '//long algorythm' block.

dseligo

  • Hero Member
  • *****
  • Posts: 1222
Re: What is good in using try..finally?
« Reply #3 on: October 07, 2021, 06:31:19 pm »
With the same logic, I do not see why it is recommended many places to use two try.. blocks nested. It is to bypass the fact that you cannot use try..except..finally, but what is the benefit of
Code: Pascal  [Select][+][-]
  1.     procedure a;
  2.       begin
  3.         Screen.Cursor := crHourglass;
  4.         try
  5.           try
  6.             // long algorithm...
  7.           except
  8.             // handle the exception or decide not to, and let it further be raised to the caller of proc a.
  9.           end;
  10.         finally
  11.           Screen.Cursor := crDefault;
  12.         end;
  13.       end;
over the second method shown above?

Benefit is that it catches exceptions and also it makes sure that 'finally' block get executed.

alpine

  • Hero Member
  • *****
  • Posts: 1069
Re: What is good in using try..finally?
« Reply #4 on: October 07, 2021, 06:42:54 pm »
The finally block gets always executed! In your second code snippet Screen.Cursor := crDefault; will be skipped if the exception is re-raised from the exception handler with raise or there is no suitable handler for the exception type.

Or if you have 'Exit' in '//long algorythm' block.
Yes!

I should correct myself once more then: The finally block gets executed in case '//long algorythm' block completes or raises an exception. Not always.  :D
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: What is good in using try..finally?
« Reply #5 on: October 07, 2021, 06:43:56 pm »
There is something else you need to consider. Code is constantly evolving. Maybe you don't use try-except because you know there is no way to exit without getting to the end part like in your example where you handle the exception.

But then, after a while, someone adds an "Exit" call in the middle of the algorithm, or changes the exception handler to only handle certain exceptions and let others pass through. Or maybe the exception handler is changed such that it can itself couse or re-raise exceptions. And if the algorithm is rather long, then someone adding something that breaks this assumption might not even realize there is no try-finally block.
While you can of course ommit the try-finally now, because now this is working completely fine, it is not very future proof.

You should always try to write your code as safe as possible. Even if this safety is not needed at the moment, you never know what happens in the future. Maybe tomorrow the project ins transferred to a drunken monkey to do the implementation, then your code should be as safe as possible to account or at least not amplify for the mistakes done by that monkey

jollytall

  • Sr. Member
  • ****
  • Posts: 320
Re: What is good in using try..finally?
« Reply #6 on: October 07, 2021, 06:49:48 pm »
Thanks.
The finally block gets always executed! In your second code snippet Screen.Cursor := crDefault; will be skipped if the exception is re-raised from the exception handler with raise or there is no suitable handler for the exception type.
My though would be that either I can handle the exception in except and then I do not need finally, code is OK without it; OR I do not know what went wrong (an exception I cannot handle), but then it might be too risky to continue with any code after that even in finally. Now I see the benefit of catching some exceptions, but re-raising some others and still do some final activity. This would however make the language improvement request seen elsewhere to allow try..except..finally..end in one block a lot of sense, so one would not need two nested try-s.
Benefit is that it catches exceptions and also it makes sure that 'finally' block get executed.
This was the unclear part. If I catch the exception then I do not need finally, as the code after the except gets executed anyway. The whole learning point for me, is that I can unhandle/re-raise some exceptions and still finally works.
While you can of course ommit the try-finally now, because now this is working completely fine, it is not very future proof.
Good point

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: What is good in using try..finally?
« Reply #7 on: October 07, 2021, 07:24:37 pm »
This was the unclear part. If I catch the exception then I do not need finally, as the code after the except gets executed anyway. The whole learning point for me, is that I can unhandle/re-raise some exceptions and still finally works.
If the code does not contain an "Exit" call then yes. But remember that exceptions like out of memory could theoretically be caused by pretty much any function (e.g. if it deals with strings this is always a danger), even those inside an except block. So better safe than sorry and always use exceptions

alpine

  • Hero Member
  • *****
  • Posts: 1069
Re: What is good in using try..finally?
« Reply #8 on: October 07, 2021, 07:35:15 pm »
As Warfley adviced wisely, you should always try to write your code as safe as possible.

The common practice is when you allocate or otherwise acquire a resource, then always deallocation or release of it must follow immediately in try...finally block and the finally should be ASAP and without second thoughts whether the enclosed block can or cannot raise an exception. This approach will minimize the chances of memory leaks and dead-locks.

Since the exception handling blocks (try...finally, try...except, raise) can change the program flow dramatically (actually a cross-boundary gotos), they must be used for what they're intended - for exceptions. It is tempting to use raise for e.g. a premature exit, but overusing them makes the program much less readable and maintainable.

Its worth noticing the Abort procedure here, https://www.freepascal.org/docs-html/rtl/sysutils/abort.html, which is such a controversial mechanism to raise a 'silent' exception and to return control to the main program loop.
« Last Edit: October 07, 2021, 07:36:48 pm by y.ivanov »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

440bx

  • Hero Member
  • *****
  • Posts: 4070
Re: What is good in using try..finally?
« Reply #9 on: October 07, 2021, 07:51:43 pm »
My though would be that either I can handle the exception in except and then I do not need finally, code is OK without it; OR I do not know what went wrong (an exception I cannot handle), but then it might be too risky to continue with any code after that even in finally. Now I see the benefit of catching some exceptions, but re-raising some others and still do some final activity. This would however make the language improvement request seen elsewhere to allow try..except..finally..end in one block a lot of sense, so one would not need two nested try-s.
I'm going to give you a piece of advice that is quite likely many OOP programmers will disagree with, which is, a bug-free program never needs a "try-finally" and extremely rarely needs a "try-except".  "try-finally" should never be used and the only times "try-except" may be acceptable is when writing a program that deals with resources that are not under its control. 

IOW, the presence of a "try-finally" is a clear indicator that the code has logical flow deficiencies and, the presence of a "try-except" is almost always an indicator of the same.

Unfortunately, the Pascal implementation of OOP often forces the use of "try-except" because it's the only way to let the caller of some code know that a problem occurred.  Lastly, keep in mind that a "try-except" is nothing more than a cross stack frame goto  mechanism which is the worst kind of goto there is.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

jollytall

  • Sr. Member
  • ****
  • Posts: 320
Re: What is good in using try..finally?
« Reply #10 on: October 07, 2021, 08:03:09 pm »
HTH.
Interesting thoughts. In my almost 40 years of Pascal, I hardly used try. Operating System calls (like file operations) have other mechanisms, Div0 should be checked in advance and avoided, etc. I only used it for some external library calls, etc., when I was not sure what can happen.
My problem was always what to do with
Code: Pascal  [Select][+][-]
  1. function MyDivide(a,b:double):double;
if b=0. Do I return 0 or nowadays NaN, etc. I often did
Code: Pascal  [Select][+][-]
  1. function MyDivide(a,b:double; var c:double):integer;
and the return value was an error code, but it is such a pain to use a result given back as a parameter.
So I made some reading and try is strongly recommended by many experts and hence I am thinking to change my typical set-up raising exceptions.
Also as said by others in this thread, try has advantages in many situations.

ASerge

  • Hero Member
  • *****
  • Posts: 2250
Re: What is good in using try..finally?
« Reply #11 on: October 07, 2021, 08:13:40 pm »
In my opinion, try finally should always be used. This is a good language construct that guarantees resource cleanup without worrying about the details. Code that does not do this will surely lead to errors not giving back the resource.

Try except is used much less often, only when you know for sure that someone's code (you would fix your own) may contain bugs, or you are trying to work with an unreliable resource that often crashes, and you know how to handle some cases.

A few years ago, here on the forum, I gave a program that did an analysis of comparing the frequency of constructions based on Delphi 7 sources. There are the same numbers as the output above. Like 1 to 70 (except:finally).

440bx

  • Hero Member
  • *****
  • Posts: 4070
Re: What is good in using try..finally?
« Reply #12 on: October 07, 2021, 08:43:37 pm »
So I made some reading and try is strongly recommended by many experts and hence I am thinking to change my typical set-up raising exceptions.
It used to be that "experts" (actually formal programming theory) recommended that a function/procedure first ensure the preconditions necessary for its successful execution were present. If the preconditions were satisfied then and, only then, would the code that implements the function be executed.  Also formal programming theory "recommended" that post-conditions be checked.  Following that rule religiously helps enormously in writing code that is bug free and totally eliminates the need for "try-finally" constructs.

In the case of division by zero, the precondition is ensuring the divisor is not zero.  How the violation of that precondition is handled depends on the program but, the point is, checking the divisor beforehand is the proper course of action, not wrapping the division in an exception handler.  That's a hack.

Also as said by others in this thread, try has advantages in many situations.
I would say that more, better and cleaner advantages are derived from religiously checking preconditions and ideally post-conditions but, I realize that's "old school" these days.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

SymbolicFrank

  • Hero Member
  • *****
  • Posts: 1313
Re: What is good in using try..finally?
« Reply #13 on: October 07, 2021, 09:13:21 pm »
I'm going to give you a piece of advice that is quite likely many OOP programmers will disagree with, which is, a bug-free program never needs a "try-finally" and extremely rarely needs a "try-except".  "try-finally" should never be used and the only times "try-except" may be acceptable is when writing a program that deals with resources that are not under its control. 

IOW, the presence of a "try-finally" is a clear indicator that the code has logical flow deficiencies and, the presence of a "try-except" is almost always an indicator of the same.

Unfortunately, the Pascal implementation of OOP often forces the use of "try-except" because it's the only way to let the caller of some code know that a problem occurred.  Lastly, keep in mind that a "try-except" is nothing more than a cross stack frame goto  mechanism which is the worst kind of goto there is.

HTH.

In other words: the only reason to use "try" is to cover up your own bugs? I totally disagree.

On a tiny microcontroller, where only your own code is running in an endless loop, you would be right. In all other cases, it is more complicated.

For example: you use a socket to communicate with some remote computer. Do you want the socket to be closed, no matter what? Because, there's probably a thread that is waiting on input. And you cannot just kill threads.

And remember: while we have a way to safely close resources with try .. finally, C++ cannot do that. We win.

440bx

  • Hero Member
  • *****
  • Posts: 4070
Re: What is good in using try..finally?
« Reply #14 on: October 07, 2021, 09:26:39 pm »
In other words: the only reason to use "try" is to cover up your own bugs? I totally disagree.
"try-finally"s often end up hiding bugs.  Not exactly a desirable feature.

For example: you use a socket to communicate with some remote computer. Do you want the socket to be closed, no matter what? Because, there's probably a thread that is waiting on input. And you cannot just kill threads.
What's really surprising is that "modern" programmers seem to have totally forgotten that operating systems, compilers and lots of very complicated software has been written without "try-finally" and suddenly, according to you, apparently no such complex software can be written without that programming crutch.

Your faulty viewpoint is no surprise and, it's quite likely widely shared among your peers.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018