Lazarus

Free Pascal => General => Topic started by: jollytall on October 07, 2021, 05:48:08 pm

Title: What is good in using try..finally?
Post by: jollytall 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?

Title: Re: What is good in using try..finally?
Post by: alpine 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.
Title: Re: What is good in using try..finally?
Post by: dseligo 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.
Title: Re: What is good in using try..finally?
Post by: dseligo 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.
Title: Re: What is good in using try..finally?
Post by: alpine 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
Title: Re: What is good in using try..finally?
Post by: Warfley 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
Title: Re: What is good in using try..finally?
Post by: jollytall 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
Title: Re: What is good in using try..finally?
Post by: Warfley 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
Title: Re: What is good in using try..finally?
Post by: alpine 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.
Title: Re: What is good in using try..finally?
Post by: 440bx 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.
Title: Re: What is good in using try..finally?
Post by: jollytall 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.
Title: Re: What is good in using try..finally?
Post by: ASerge 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).
Title: Re: What is good in using try..finally?
Post by: 440bx 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.

Title: Re: What is good in using try..finally?
Post by: SymbolicFrank 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.
Title: Re: What is good in using try..finally?
Post by: 440bx 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.

Title: Re: What is good in using try..finally?
Post by: alpine on October 07, 2021, 09:39:34 pm
*snip*
In other words: the only reason to use "try" is to cover up your own bugs? I totally disagree.
Me too.

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.
I was just about to write something like that, using TStream's is another example (or using components that embed TStream). You can't just ignore the possibility for an exception to be raised dealing with periphery, communication parties, etc. It is just not realistic.

Searching in RTL source, I find about 300 hits for raise statement. Can't believe some can work with it without exception handling blocks and only with pre-/post- conditions.

And remember: while we have a way to safely close resources with try .. finally, C++ cannot do that. We win.
There are techniques for mimicking the finally in C++, in general that is less needed there, but yes - I constantly miss that simple fpc feature.
Title: Re: What is good in using try..finally?
Post by: alpine on October 07, 2021, 09:52:47 pm
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.
No, I'd never forget that. I'm fully comfortable writing in plain C, without any try stuff.

But when it comes to writing in FPC you have to take in account the reality: RTL, LCL abound with exceptions.
C library will never throw anything at your face.
Title: Re: What is good in using try..finally?
Post by: skalogryz on October 07, 2021, 10:00:34 pm
"try-finally"s often end up hiding bugs.  Not exactly a desirable feature.
how can try..finally hide bugs?

try..except can. (it is its purpose, pretty much), but try..finally?
Title: Re: What is good in using try..finally?
Post by: Warfley on October 07, 2021, 11:23:41 pm
HTH.
First, this is something I wondered often when reading your posts with respect to exceptions, why do you associate them with OOP? They are not part of OOP, in fact even Haskell has them and Haskell isn't even a procedural language let alone an OOP language.

Second, with respect to try-finally, I've been working with a lot of C code and the main reason for memory leaks in my experience is that algorithms that they use return to exit the function early but forget to free the allocated resources. Something like this:
Code: Pascal  [Select][+][-]
  1.   New(MyData);
  2.   // do something
  3.   if ExitCondition then
  4.     Exit; // Here a dispose would be required
  5.   // other stuff
  6.   Dispose(MyData);
It is very easy to forget such a single line, especially if you have like 4 or 5 exit locations. Try-finally makes two improvements to resource management, first it eliminates the risk to forget the freeing at some point in the code, second if done consistently it is very easy to spot memory leaks. If somewhere is an allocation you look at the following line. If it is not directly followed by try-finally then there is a possible memory leak.

Lastly about exceptions and try-except. It's not like before exceptions as language constructruct, there still where exceptions. This is usually done by having a dedicated return value (e.g. -1) to indicate an error or have multiple outputs (e.g. by using pointers/var or out params) and a global variable with more detailed information (e.g. errno on linux). Example from the socket api:
Code: Pascal  [Select][+][-]
  1. sock := fpSocket;
  2. if sock < 0 then
  3.   WriteLn('Error: ', errno);
Generally speaking, this is not so differently from how exceptions are used:
Code: Pascal  [Select][+][-]
  1. try
  2.   sock := Socket;
  3. except on E: SocketError do
  4.   WriteLn('Error: ', E.code);
  5. end;
But there is a key advantage of exceptions over error codes. Exceptions force you to act. If an exception is not handled, it will kill your application which guarantees that your application will never run in an errorneous state. Using old school exception handling this is not the case. Look at the following code from the FCL currently shipped with the fpc:
Code: Pascal  [Select][+][-]
  1.   fpsendto(sock,@qry,qrylen+12,0,@SA,SizeOf(SA));
  2.   // Wait for answer.
  3.   RTO:=TimeOutS*1000+TimeOutMS;
  4.  
Here you see that no error handling is done. If an error occurs, it is just completely ignored and the program continues as if it was successful.

Sure all of these things can be said that it is just due to bad coding and the programmers should "man up" and "learn to write good code" (an attitude that many priests of the gospel of C share) but fact is, it is easy to make mistakes and the goal of language design is to minimize the chance to do such errors and to mitigate the harm they do. And Exceptions do this pretty well
Title: Re: What is good in using try..finally?
Post by: wp on October 07, 2021, 11:32:07 pm
Most people having problems with "try-except" and "try-finally" misunderstand the meaning of these constructs. They think they can prevent an exception - no, the exception already has happened and cannot be undone!

The "try-except" determines how the program will respond to the exception: Display an error message by ShowMessage? Display a MessageDlg with an assigned special help context to give further information? WriteLn an error message? Simply abort the program? Ignore it? In my experience there is nothing wrong in most cases to avoid "try-except" blocks and to keep the standard exception error dialog. I agree that this dialog appears very drastic ("risk data corruption, kill the application"), but you can avoid this by adding a TApplicationProperties to the form and setting its ExceptionDialog property to aedOKMessageBox which makes the exception dialog to show only the exception message, not the "risk data corruption" etc.

But far more important than "try-except" is "try finally". It simply makes sure that the code in the "finally-end" block is always executed, no matter what happened in the "try-finally" part. Suppose the code in the very first post: The screen cursor is set to crHourglass before a lengthy calculation. When an exception occurs inside the try-finally block, or even when there is an "exit" somewhere within "try-finally"  code execution is absolutely continued in the "finally-end" part and this is where the cursor is reset to crDefault. Without the finally-end part, the program would always show the hour-glass cursor!

Another important ingredient is the "raise" instruction, particular in re-usable units or packages. "raise" is used to fire an exception. Suppose, a complicated calculation under some circumstances will have a zero in the denominator of a division. Of course you can continue with the calculation which will fire an exception, but the error message will be "division by zero at address..." (or similar) - this is very diffuse and of little help. On the other hand, knowing that an error will occur, you could exit the calculation and display a message box saying "Calculation xyz cannot be completed because of division by zero". This is fine because the user knows where the problem is. But is it ok to show a messagebox? When the unit in which this happens is reusable I would say no, because: What if the message should be translated to other languages? What if the calculation is used by a console program which cannot display a messagebox, but wants a WriteLn instruction? You don't know what will be appropriate in all use cases of this unit. You have much more flexibility when you "raise" an exception then the user can decide in his exception handler what to do.

So, in summary:
- Whenever you allocate memory or change something before an action which may go wrong protect that by using a "try-finally-end" block.
- Only in very rare cases it is needed to use a dedicated "try-except" exception handler.
- In reusable code raise exceptions yourself rather than relying on builtin exceptions.
Title: Re: What is good in using try..finally?
Post by: Warfley on October 08, 2021, 12:03:09 am
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.
Whats interesting about this is that many of the large C applications are transitioning to a modern language like C++ or Rust having all of these neat features like exceptions. And most new applications use modern languages from the get go.
Firefox, Gimp, LLVM, KDE, QT, Webkit, Blink engine, GCC, etc. all are written in or are transitioning to C++. In fact, except for the Linux kernel pretty much all of the largest open source projects are transitioning away from C with the main reason being the features like Exceptions and OOP (And the reason why Linux hasn't switched is because Linus is a purist)

Arguments from popularity aren't good arguments to begin with, but in this case it doesn't even hold, because all these big projects are transitioning away from pure C
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 12:10:02 am
But when it comes to writing in FPC you have to take in account the reality: RTL, LCL abound with exceptions.
C library will never throw anything at your face.
you have a point there but, it shows that the use of exceptions is forced on the programmer to deal with code whose design leaves something to be desired.



how can try..finally hide bugs?
Usually due to either a programming mistake or, what is the same an invalid assumption made in the code.  The finally ends up hiding that.



First, this is something I wondered often when reading your posts with respect to exceptions, why do you associate them with OOP?
I associate them with OOP because there are OOP constructs, properties come to mind, where when something goes wrong there is no mechanism to return an error code to the caller.  That forces the use of exceptions. 



They are not part of OOP, in fact even Haskell has them and Haskell isn't even a procedural language let alone an OOP language.
They aren't formally part of OOP but without them there are a good number of OOP programming constructs that would not be feasible.   Exceptions, at least in Object Pascal, are necessary to make OOP usable.

Second, with respect to try-finally, I've been working with a lot of C code and the main reason for memory leaks in my experience is that algorithms that they use return to exit the function early but forget to free the allocated resources.
Memory leaks are the results of programming bugs and "try-finally" constructs don't guarantee a program/algorithm to be bug free.

It is very easy to forget such a single line, especially if you have like 4 or 5 exit locations.
Particularly when there are multiple exit points, try-finally(s) should be avoided.  The generated code is, more often than not, an atrocity.

Try-finally makes two improvements to resource management, first it eliminates the risk to forget the freeing at some point in the code, second if done consistently it is very easy to spot memory leaks.
A programmer can "forget" (or "miscalculate") that a "try-finally" is needed, particularly when they are nested (which is quite common.)  As far as memory leaks, a little self-checking in the program can catch those without any "try-finally" anywhere in the code.

This is usually done by having a dedicated return value (e.g. -1) to indicate an error or have multiple outputs (e.g. by using pointers/var or out params) and a global variable with more detailed information (e.g. errno on linux).
A return indicating an error occurred seems to be too simple for many programmers these days.  As far as global variables, the need for those is a clear indication of a design deficiency.  Acceptable only in throw-away or proof of concept code.

But there is a key advantage of exceptions over error codes. Exceptions force you to act.
It's a bit "peculiar" to have to force programmers to handle errors.  I really don't think that exceptions forcing a programmer to pay attention to errors is a good thing.  Programmers should write code that handle errors without being forced to do it.

If an exception is not handled, it will kill your application which guarantees that your application will never run in an errorneous state.
On the contrary.  As you pointed out, it is common in the life of a program to make changes and/or additions.  It's not as uncommon as it should be to find exception handlers that were added at some point in time that catch exceptions they were never meant to catch and, as a result, handled them in a way that is not the way they should be handled but, since the program keeps running it leaves the impression that everything is honky-dory.

<snip> programmers should "man up" and "learn to write good code" (an attitude that many priests of the gospel of C share)
Personally, I believe programmers should "programmer up" and accept that their first responsibility is to write decent code if they want to call themselves programmers.  That's the difference between a programmer and an amateur who programs as a hobby.  The amateur throws code at the computer and as long as it seems to work or works most of the time, the program is done.  try-finally and try-except are whipped cream to spread generously on code that is "culinary" questionable.

it is easy to make mistakes and the goal of language design is to minimize the chance to do such errors and to mitigate the harm they do. And Exceptions do this pretty well
It is easy to make mistakes... I've noticed that too plenty of times in my own code.  If a program has an error, the ideal result is program crash.  That way the problem is obvious and its solution required immediately.  Solving the problem is the "mitigation".



On the other hand, knowing that an error will occur, you could exit the calculation and display a message box saying "Calculation xyz cannot be completed because of division by zero". This is fine because the user knows where the problem is. But is it ok to show a messagebox? When the unit in which this happens is reusable I would say no, because: What if the message should be translated to other languages? What if the calculation is used by a console program which cannot display a messagebox, but wants a WriteLn instruction? You don't know what will be appropriate in all use cases of this unit. You have much more flexibility when you "raise" an exception then the user can decide in his exception handler what to do.
It's not more flexible.  The routine that detects an error is often not the routine where the error should be handled.  It simply returns an error code to the caller who will float it up as necessary until it reaches the routine that is designed to handle that error or errors in general.  When debugging the code the flow is visible and obvious, when using exceptions execution jumps all over the place.  That jumping all over the place can also happen with try-finally (usually when multiple exit points exist.)



Firefox, Gimp, LLVM, KDE, QT, Webkit, Blink engine, GCC, etc. all are written in or are transitioning to C++. In fact, except for the Linux kernel pretty much all of the largest open source projects are transitioning away from C with the main reason being the features like Exceptions and OOP (And the reason why Linux hasn't switched is because Linus is a purist)

Arguments from popularity aren't good arguments to begin with, but in this case it doesn't even hold, because all these big projects are transitioning away from pure C
In the case of C and C++, I understand why C programmers would want to transition to C++. When I write C code, I run the compiler in C++ mode because I get much better type checking than in C mode not to mention true types instead of the C mostly meaningless type gimmicks.  That said, there is no way I'd infect my code with OOP stuff.



Title: Re: What is good in using try..finally?
Post by: wp on October 08, 2021, 01:14:08 am
how can try..finally hide bugs?
Usually due to either a programming mistake or, what is the same an invalid assumption made in the code.  The finally ends up hiding that.
This sounds as if you are confusing "try-finally" and "try-except". Show a sample code snippet in which "try-finally" hides a bug? "try-finally" has only one purpose: to protect resources in case of an error, no error handling!
Title: Re: What is good in using try..finally?
Post by: Warfley on October 08, 2021, 01:18:38 am
Memory leaks are the results of programming bugs and "try-finally" constructs don't guarantee a program/algorithm to be bug free.

...

It's a bit "peculiar" to have to force programmers to handle errors.  I really don't think that exceptions forcing a programmer to pay attention to errors is a good thing.  Programmers should write code that handle errors without being forced to do it.

...

Personally, I believe programmers should "programmer up" and accept that their first responsibility is to write decent code if they want to call themselves programmers.  That's the difference between a programmer and an amateur who programs as a hobby.  The amateur throws code at the computer and as long as it seems to work or works most of the time, the program is done.  try-finally and try-except are whipped cream to spread generously on code that is "culinary" questionable.
But it is exactly what I was critizising. This form of entiteled elitism. A language should be designed in a way that it enforces good and bug free programming. Saying that programmes should just be better at writing code helps no one. If your goal is to increase the code quality, you need to create your language such that it steers the programmer in the right direction.
Sure you don't need try-finally or try-except, you can design your code in a way that you don't need them. But history has shown that programmers handle errors if they don't fly in their faces, or create memory leaks if there is no automatic mechanism supporting them. So the language fixes the problem by its design by giving tools to handle this on the language level.

The best example for this is IMHO null/nil pointers. They are one of the largest source of errors in programming and as C.A.R. Hoare called them, his "billion dollar mistake". The problem is that any pointer can be null/nil at any time, therefore each function needs to check the pointers, but most people don't do that running in access violations.
This is probably the most wide spread problem in programming, so many language (e.g. Swift, Kotlin, Typescripts) solved this on a language level, by simply removing null as a pointer value (and replacing it with an optional type).
It's a very elegant solution that completely erases one of the largest problems in programming.

Good programmers can write good code with any language. But most people are not good programmers but average programmers, and the tooling should be optimized for them.
Also you must think of the alternatives. If people can't use exceptions they might use stuff like signals to handle errors (yep, I've seen such C code) and this is just strictly worse on every level

Particularly when there are multiple exit points, try-finally(s) should be avoided.  The generated code is, more often than not, an atrocity.
I don't care for the generated code. Most of the time I don't even look at it. The first and foremost goal (after that the code should work of course) is that the high level code is easiely readable and maintainable. If that results in "bad" assembly I don't care as long as it works as expected/as the language manual promises and I don't run into performance issues, it could be as shit as ever.
And only having to write one free that will cover all the exit points that are currently in the program as well as all that will be added in the future just wins hands down here.

A programmer can "forget" (or "miscalculate") that a "try-finally" is needed, particularly when they are nested (which is quite common.)  As far as memory leaks, a little self-checking in the program can catch those without any "try-finally" anywhere in the code.
Thats why its considered good practice to always include it, even if you think it is not necessary. But sure you can forget a try-finally, but the chances of forgetting try-finally (especially if you trained yourself to always use it in combination with free) are lower than forgetting a single free from 5 exit points. No solution is perfect, it's about minimizing the error potential.

A return indicating an error occurred seems to be too simple for many programmers these days.  As far as global variables, the need for those is a clear indication of a design deficiency.  Acceptable only in throw-away or proof of concept code.
A return value indicating an error is not always a great solution. First return values can be easiely ignored. As I said, errors should always be checked and the language should enforce this. Making it a return value is the weakest form of doing so. And as has been shown time and time again, people just don't check for erros. Just look at the fpsendto example I've posted earlier. This stuff is everywhere.
Second it makes the function calls much more complicated. For example an out of memory error can happen everywhere dynamic memory is used. Which means that any such function needs to have a return code encoding this error. But in fact, if an OOM happens, I want to print an error message and just crash the program (because there is nothing I can do really at that point), so here an exception is the way better alternative, as it does not need to be incorporated in every functions return value, while also, being unhandled, will crash the program as I want it to

On the contrary.  As you pointed out, it is common in the life of a program to make changes and/or additions.  It's not as uncommon as it should be to find exception handlers that were added at some point in time that catch exceptions they were never meant to catch and, as a result, handled them in a way that is not the way they should be handled but, since the program keeps running it leaves the impression that everything is honky-dory.
This is I think actually quite a big problem, but a problem that could be solved by the language/compiler. I like to take a look at how other languages target certain problems and here Java is a great example.
In Java, if your function can throw an exception, the function needs to be tagged with that exception. If you call this function within your code the compiler checks if either, you catch that exception, or the calling function is also tagged for that exception (i.e. it can be propagated to the next stack frame).
It can be thought of as a function that can either return a normal value or an exception. And when calling that exception you need to check what type the return value is to use it or to handle the exception. To propagate the exception the return type of your function must also have the ability to express this exception (this is actually how haskell implements exceptions, as it is a functional language it is simply encoded in the return type).
This first of all makes sure that the programmer a. excatly knows what exceptions can be raised in which parts of the program and b. that these exceptions are handled even if they would never occur in any test run (which is the problem you have in object pascal, where you only see that you are missing an exception handler once it happens).

The next step is then to give compiler warnings if the exceptions are to broad. If you are having an exception handler for an exception that can't occur, or you tagged your function with an exception that can't happen, the compiler will throw a warning. If you have an exception handler that catches way to generalized exception types (like the base classs Exception) it will throw a hint. IDEs also have the functionality to automatically generate all required except blocks and remove overgeneralized

Yes it is a problem that many people run into, that they just write something like:
Code: Pascal  [Select][+][-]
  1. except on E: Exception do
  2. // or completely general
  3. except
which over catches exceptions. But with the right compiler and tooling support, notifying the user when it happens and helping to resolve these problems, this can easiely be avoided. It's just not a feature FPC has.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 03:15:30 am
Show a sample code snippet in which "try-finally" hides a bug? "try-finally" has only one purpose: to protect resources in case of an error, no error handling!
Here is a complete program that uses try-finally and is very misleading and quite likely completely incorrect.
Code: Pascal  [Select][+][-]
  1. {$APPTYPE       CONSOLE}
  2.  
  3. {$TYPEDADDRESS  ON}
  4.  
  5. {$LONGSTRINGS   OFF}
  6.  
  7. { --------------------------------------------------------------------------- }
  8.  
  9.  
  10. program _tryfinally;
  11.  
  12.  
  13. uses
  14.   Windows,
  15.   sysutils
  16.   ;
  17.  
  18. { missing in Delphi 2 }
  19.  
  20. function GetConsoleWindow : HWND; stdcall; external 'kernel32';
  21.  
  22. var
  23.   Dc  : HDC;
  24.   Wnd : HWND;
  25.  
  26. begin
  27.   writeln;
  28.   writeln;
  29.  
  30.   Wnd := GetConsoleWindow();
  31.  
  32.   try
  33.     Dc := GetDC(Wnd);
  34.   finally
  35.     { the following call will give the impression the Dc is released.  In     }
  36.     { this case, it isn't because the parameters are reversed and, as is      }
  37.     { the common case, the result of the call is not checked.                 }
  38.  
  39.     { even if the parameters had not been reversed, if the call had been      }
  40.     { made in a different thread than the one that called GetDC, the release  }
  41.     { would have failed.                                                      }
  42.  
  43.     ReleaseDC(Dc, Wnd);  { typical in finally(s) - no error checking          }
  44.  
  45.     { this is conceptually incorrect but, it seems to work - MS specifically  }
  46.     { states this should not be done.  It is unknown if this call leaves      }
  47.     { internal inconsistencies behind even though it reports success.         }
  48.  
  49.     if not DeleteDC(Dc) then writeln('  DeleteDC failed');
  50.   end;
  51.  
  52.  
  53.  
  54.   writeln;
  55.   writeln;
  56.   writeln('press ENTER/RETURN to end this program');
  57.   readln;
  58. end.          
In the program above, the call to ReleaseDC has the parameters reversed, that causes the call to fail but, as is the most common case, no error checking is done, thus, if that were the only call, a GDI handle would still be leaked. 

The insidious problem is that if the programmer uses a utility to check for leaked handles he/she will notice that a handle is leaked but, in a large program, the automatic assumption is that the leak isn't happening in that code because it is in a "finally" section, which is incorrect because the problem is in the parameters being reversed.

The second part is more insidious.  DeleteDC - which should not be used in that case - succeeds and no handle is leaked but it is extremely likely that the internal housekeeping done by GDI has gotten messed up because DeleteDC does not operate the same way as ReleaseDC.   Bottom line is the presence of the "finally" gives a false sense of confidence that everything is fine when it is not.

This is one example that came to mind because I have personally made the mistake of reversing the parameters in ReleaseDC but, I have read other people's code where I've seen other cases where the presence of the "finally" hid a subtle bug.



But it is exactly what I was critizising. This form of entiteled elitism. A language should be designed in a way that it enforces good and bug free programming. Saying that programmes should just be better at writing code helps no one.
Honestly, I don't think it's a form of elitism.  When someone decides to perform an activity, I believe they should be motivated to become good at it, ever better if possible.  Therefore, I do think a programmer should become ever better at writing code.  If not, they should choose something they want to get really good at.  If that makes me an elitist, so be it.

If your goal is to increase the code quality, you need to create your language such that it steers the programmer in the right direction.
I completely agree with that. Where we differ in opinion is that "try-finally" doesn't accomplish that.  It goes in the opposite direction.

<snip> or create memory leaks if there is no automatic mechanism supporting them. So the language fixes the problem by its design by giving tools to handle this on the language level.
and that's how we end up with languages like Java.  For throw away stuff or prototyping something, it's perfectly fine, even handy but, when the goal is to produce a really good program things like Java are a joke.



Good programmers can write good code with any language. But most people are not good programmers but average programmers, and the tooling should be optimized for them.
I have to admit, I'm not sure that it is possible to write good code with any language.  Some languages make accomplishing that goal exceedingly difficult.  As far as tools/features that enable a programmer to write better code, I don't include "try-finally" among them.  On the contrary, I see that construct as encouraging not designing because the option of using a "try-finally" is there.

If that results in "bad" assembly I don't care as long as it works as expected/as the language manual promises and I don't run into performance issues, it could be as shit as ever.
I believe it is possible to write code that is easy to understand and maintain and ensure the resulting assembly code is, at least, decent.  That's important because if the code is lousy, it will eventually be a problem either in maintenance or in performance.  While performance should not be at the top of the totem pole, it shouldn't be neglected either.

Thats why its considered good practice to always include it, even if you think it is not necessary. But sure you can forget a try-finally, but the chances of forgetting try-finally (especially if you trained yourself to always use it in combination with free) are lower than forgetting a single free from 5 exit points. No solution is perfect, it's about minimizing the error potential.
seems to me that it is much simpler and easier to simply check pre-conditions and post-conditions.  That way the code isn't peppered with "try-finally", "try-except" and if statements for on-going piecemeal checks.

A return value indicating an error is not always a great solution. First return values can be easiely ignored. As I said, errors should always be checked and the language should enforce this. Making it a return value is the weakest form of doing so. And as has been shown time and time again, people just don't check for erros. Just look at the fpsendto example I've posted earlier. This stuff is everywhere.
Those who make it a habit to ignore errors shouldn't be forced to deal with them, they should be encouraged to do something else they care more about. 


Second it makes the function calls much more complicated. For example an out of memory error can happen everywhere dynamic memory is used.
Running out of memory isn't really an error, it's a program state. The program can simply inform the user, that there is insufficient memory to do whatever it was they wanted to do.

As far as exceptions go, I find they unnecessarily complicate the code, not to mention maintenance and debugging.  The only use I find justified for exceptions is when accessing resources that are not under the program's control and in parameter validation and, that last one, _only_ during development.
Title: Re: What is good in using try..finally?
Post by: wp on October 08, 2021, 10:44:36 am
Here is a complete program that uses try-finally and is very misleading and quite likely completely incorrect.
Using try-finally does not mean that you can assume that the finally part is error-free. I do not see why this is an argument for not to use try-finally.

Run the attached demo. Click the "With try-finally" button. This changes the Screen.Cursor to the hourglass  and then performs some stupid calculation which creates a divide-by-zero error. Since the calculation is inside a try-finally block, the original Screen.Cursor can be restored. Now click the "Without try-finally" button. This does the same calculation, but now without a try-finally block. Now, after handling the exception the cursor is NOT restored and remains like this for the end of the program.

You will probably say: I can check the denominator in the calculation, set an error variable and restore the cursor if the error variable is set. But this is only a very simple example. Suppose the calculation is very complicated, requires several units, and all kinds of error can happen. There is a high chance that you'll miss one of the error conditions in this approach. Try-finally, on the other hand, is a universal mechanism regardless of where and which kind of error happened.

The argument "don't use try-finally it makes bugs in the finally block hard to find" is like "stop programming because bugs are hard to find".
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 11:42:29 am
Using try-finally does not mean that you can assume that the finally part is error-free.
Agreed but, that's an assumption that is not rare to see in "finally" code.

I do not see why this is an argument for not to use try-finally.
I have to concede that the example I gave left something to be desired but, it was the only one that came to mind at the time. However, your example reminded me of code in a "finally" that would hide a bug in the "try" section of the code.  I used your example project.  I'll post the changes after I comment on the other points you made.

Run the attached demo.
I did and, it works.  I never suggested "try-finally" doesn't work.  now.. on to the rest of what you mentioned...

You will probably say: I can check the denominator in the calculation, set an error variable and restore the cursor if the error variable is set.
Checking the denominator is the right thing to do and if it is zero restore the cursor and either return an error code to the caller or possibly set the result to a predetermined value that is "convenient" whenever the denominator is zero.

But this is only a very simple example. Suppose the calculation is very complicated, requires several units, and all kinds of error can happen. There is a high chance that you'll miss one of the error conditions in this approach. Try-finally, on the other hand, is a universal mechanism regardless of where and which kind of error happened.
Honestly I don't think that's a good argument.  If the calculation is very complicated then it should be broken into a number of simple steps.  In particular, the denominator should be calculated separately so it can be checked.  Using "try-finally" to justify the existence of code that should be simplified isn't what I consider a positive aspect of "try-finally".

The argument "don't use try-finally it makes bugs in the finally block hard to find" is like "stop programming because bugs are hard to find".
Now it's a good time to post the change I made in your code which shows how "try-finally" can hide bugs.

I just made one small change in TForm1.Button1Click, now it reads:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   i: Integer;
  4.   x: Double;
  5.  
  6.   m : HMODULE;  { added }
  7.  
  8. begin
  9.   Screen.Cursor := crHourglass;
  10.   try
  11.     m := GetModuleHandle(pchar($7FFE0000));  { added }
  12.  
  13.     for i := 0 to 100 do
  14.       x := 1.0 / sin(x);
  15.   finally
  16.     Screen.Cursor := crDefault;
  17.   end;
  18. end;
  19.  
In the original code, the invalid value of "m" was used but, the corrective actions done in the "finally" didn't solve the problem, on the contrary, it hid it because it wasn't expecting that kind of problem.  The net effect was, the program ran but, the information it showed was obviously incorrect.

Title: Re: What is good in using try..finally?
Post by: jollytall on October 08, 2021, 12:04:46 pm
Thank you all for the detailed answers and even the debate. I found it very useful. It is a pretty, the topic was moved, as in my experience most people only read the top sub-forum and not others, like this one. As the saying says, if you want to really hide something nobody ever finds, just put it on the second page of google results :-).
Anyway, I learnt a lot and hereby I summarize my takeaway. As seen above, opinions differ, so I cannot think that my conclusions are the "right" ones.
Sorry, I do not put all the quotes in, to maintain readability.
Being an old-school guy who tries to use whatever new, modern tool is available as long as it is not overused, I am forming my "programming rules" around try as follows. It is a bit like a tutorial, for someone, who might find it and can learn from it.

try..finally and try..except are modern tools to handle error, although under the hood they are still if-s and jumps just like any other code. While it helps to automate different things, it also adds an overhead to the code.
An immediate conclusions: Do not use them if no error can occur, especially if something is executed multiple times (like a loop running in a billion times). Later I cover the finally bit, what only makes sense if there is something to do finally (typically heap memory or hardware release), while the except bit can be placed higher in the calling hierarchy reducing the overhead significantly.

try..finally
and try..except are if-s and jumps, so they theoretically can be used for other purposes. The general rule is that one should use it only for real exceptions, not for normal process flow. It sounds simple, but far not that easy in real life (especially if one likes this structure). Look at the next example:
Code: Pascal  [Select][+][-]
  1. procedure HireEmployee;
  2.   var
  3.     Age : integer;
  4.   begin
  5.   writeln('How old are you?');
  6.   readln(Age);
  7.   try
  8.     if Age<14 then raise ExceptionChild;
  9.     if Age<18 then raise ExceptionYoung;
  10.     ProcessApplication;
  11.   except
  12.     On E:ExceptionChild do writeln('You are a child, cannot work here');
  13.     On E:ExceptionYoung do writeln('You are too young, you need your parents'' approval to work here');
  14.     end;
  15.   end;
  16.  
It is perfectly working, but abuses the structure and should not be used like this. On the other hand a similar if..raise can be OK in the retirement home age checking. If someone is younger than 18 there then it can be a real programming error (remember Y2K?) and need to be handled as an exception. (Funfact: after I wrote this example, I just found C++ tutorial https://www.w3schools.com/cpp/cpp_exceptions.asp (https://www.w3schools.com/cpp/cpp_exceptions.asp) recommending try for just this particular check...)

One can use try..except or try..finally but not both. From what I learnt from this discussion is that it is a rare usecase (see later) when both of them would be needed and then two try blocks embedded can be used. I saw somewhere a language improvement request to allow try..except..finally..end, but it is not implemented.

Programs can be written without try at all. Actually our own code can always be made like that. I write programs for over 40 years (almost all the time Pascal) and do not remember any GPFault/SegFault, Memory leak, Div/0 in a "finished" program. Even external libraries can typically be used without try, most of them have a mechanism to notice errors through return codes. It can be an unusual value in the result of the function, or can be that the result of the function is actually the return code and the real result is passed as a var parameter, or the return code is a var parameter, or the return code is a global variable. We saw it all, but the world is moving towards exceptions, so it is sometimes almost unavoidable to use them when using recent libraries.

As per statistics finally is 70X more used than except. Still to me try..except is the more natural use (just like in C++ there is only try..catch). So my first few usecases below are try..except before I get to try..finally.

Usecase 1 - Calling an external library

In my experience, if the external library is raising exceptions, it is the best to capture it immediately and thus do not let it "pollute" the rest of my code:
Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     try
  4.       CallExternalFunction;
  5.     except
  6.       Writeln('Something went wrong...');
  7.     end;
  8.   end;
  9.  
If the handling is close to the call, it is a readable, easy to maintain the code, we know exactly who raised the error, etc. Leaving the exception handling for later can create very weird, hard-to-trace errors. If the external function communicated its problem differently (return code) then obviously that has to be handled and I would be reluctant to raise an exception. So instead of
Code: Pascal  [Select][+][-]
  1.   try
  2.     if CallExternalFunction < 0 then raise ExceptionExternal;
  3.   except
  4.     Writeln('Something went wrong...');
  5.   end;
  6.  
I would simply write
Code: Pascal  [Select][+][-]
  1.   if CallExternalFunction < 0 then
  2.     Writeln('Something went wrong...');
  3.  

Usecase 2 - Access to resources (hardware, network, file, etc.)
Just like in the above case, the error is beyond our control, and if the call can raise exceptions, I would try to catch it as soon as possible.

Usecase 3 - Let the operating system do its job, instead of we do it it
If I had a "fancy" divide function, in the old school I would write the core of it, like
Code: Pascal  [Select][+][-]
  1.   if Denominator = 0 then
  2.     begin
  3.     Writeln('Cannot divide, Denominator is zero');
  4.     result := 0;
  5.     end
  6.   else
  7.     result := Numerator/Denominator;
  8.  
The problem is that if I have many divisions I need an if before it every time and that might kill the readability of my code. So, here I can switch to exceptions:
Code: Pascal  [Select][+][-]
  1.   try
  2.     result := Numerator/Denominator;
  3.   except
  4.     Writeln('Cannot divide, Denominator is zero');
  5.     result := 0;
  6.   end;
  7.  
Think or even more "hidden" potential errors. Theoretically before calling any function, one would need to check that there is enough place left in the stack to create the necessary local variables. Also before any memory allocation, one would need to check that the heap has enough place for the object. I cannot imagine anyone doing all these checks.

So far easy. So far I had known it. Now, back to my original post. If I handle the exception then the program execution continues after the except block and I can release all the resources I allocated (memory, hardware) or reset the ones I changed (like the Cursor). Why do I need try..finally and what happens to the exception that caused the problem at the first place. This is what I learnt now.

Usecase 4 - No exception, but multiple exit points
If I have three algorithms to solve a problem, I can do (incorrectly):
Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     Screen.Cursor := crHourglass;
  4.     try
  5.       if Solved1 then exit;
  6.       if Solved2 then exit;
  7.       if Solved3 then exit;
  8.       Writeln('Cannot solve');
  9.     except
  10.       // meaningless code, as no exception is raised (unless in one of the SolvedX, but that is beyond the point now
  11.     end;
  12.   Screen.Cursor := crDefault;
  13.   end;
  14.  
The result is that the Cursor remains crHourglass if the problem is solved. I personally like exit, but I do remember some professional companies explicitly forbid to use it: One method can have only one exit point.
I would allow multiple exits, but then to me exit is exit, so I would not allow exit with finally. That is far too confusing to me, but it might be my old school.
Anyway the try..finally works well in this case.

Usecase 5 - We do not want to handle the exception
This is the second big learning for me.
Actually it is wrong to handle exceptions that occurred in our own code. If we notice something wrong (e.g. an underage employee candidate) and can handle it then it should be handled through normal, old school mechanisms. (I know it is debatable, but this is my takeaway!) We shall only raise an exception if we cannot handle it and want to inform the caller about the failure. So, typically we do not handle the exception raised in our function. Since there is no try..end structure (it is clearly meaningless, this is why!), if we return to the caller after an exception, the code to release the resource is never used.
It is the same if the exception occurs in a function we call and we are unable or unwilling to handle it. The exception goes back to the first try.. level and stops there, but any code in between is never executed. This is when try..finally comes into the picture.
Code: Pascal  [Select][+][-]
  1.   Screen.Cursor := crHourglass;
  2.   try
  3.     if Age<14 then raise ExceptionChild;
  4.     if Age<18 then raise ExceptionYoung;
  5.     ProcessApplication;
  6.   finally
  7.     Screen.Cursor := crDefault;
  8.     end;
  9.  
The exceptions are sent to the caller, signing that we cannot process the job application, but still the Cursor is reset.

One thing that bothered me, still. Why is it 70X more frequent to use try..finally than try..except?
try..finally is logically used a lot, especially in OOP, where objects are created in the Heap and need to be released. In old school OOP even this was not necessarily true, as objects could be in the stack and released automatically once the function returned. With classes it changed and need to be released. As most components we use today are classes, it makes memory leak prevention a priority.
But why exceptions are not handled close to the error, i.e. many-many times in our codes? One answer is given above, i.e. if it can be solved, it is not an exception. The other answer is that if an exception is handled, from that moment on, it does not exist and the program runs happily (i.e. unaware) until it crashes. So, it is better to let the exception raise as high as the point where it can really be handled efficiently. Imagine something like:
Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     try
  4.       c := a/b;
  5.     except
  6.       writeln('Div/0');
  7.     end;
  8.   end;
  9. procedure b;
  10.   begin
  11.     try
  12.       c := a/b;
  13.     except
  14.       writeln('Div/0');
  15.     end;
  16.   end;
  17. // and so on
  18. procedure z;
  19.   begin
  20.     try
  21.       c := a/b;
  22.     except
  23.       writeln('Div/0');
  24.     end;
  25.   end;
  26. procedure All;
  27.   begin
  28.   a;
  29.   b;
  30.   // and so on
  31.   z;
  32.   end;

vs.

Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.   c := a/b;
  4.   end;
  5. procedure b;
  6.   begin
  7.   c := a/b;
  8.   end;
  9. // and so on
  10. procedure z;
  11.   begin
  12.   c := a/b;
  13.   end;
  14. procedure All;
  15.   begin
  16.     try
  17.       a;
  18.       b;
  19.       // and so on
  20.       z;
  21.     except
  22.       writeln('Div/0');
  23.     end;
  24.   end;
Not only the first is much longer having all the try..except blocks, but also All will call a, b, .. z even if the first one fails, because a hides its error. Maybe later in the program it creates a much bigger problem (e.g. DB corruption). The second approach stops the whole processing, if any of the a, b, .. z. fails.
These two explain why try..finally is frequent and try..except is rare giving a surprising ratio.

And my last wondering, whether try..except..finally would be needed or not.
Well, as said, most of the exception are not handled so try..finally is enough. If the exceptions are handled the final activities can go after the try..except..end block. So, the only times when both except and finally can be necessary is when we want to handle exceptions and also we have multiple non-exception exit points or when we only want to handle some of the exceptions, but not all.
The first is clearly a bad programming practice to me. I already mentioned the danger of using exit, but if we use it and also want to use exception handling, it is very important to know whether the final activity is needed in all cases, or only if there is an early exit or only if there is an exception. A combined try..except..finally would be unclear not talking about the possibility of allowing try..except..finally and try..finally..except. I think it would confuse everyone. So, I agree that even if one wants to use exit and exception handling at the same time, using of nested try.. blocks is the right approach.
The second is also a bit controversial to me. Difficult to imagine a situation, where I handle some of the exceptions raised by the functions I call, but also either do not handle some exceptions received (i.e. let it pass by me) or raise my own ones, and at the same time I still also want to use a finally block. If there is such a rare case, I would agree to use two nested try blocks, making it also clear what is executed when and in what sequence.
Title: Re: What is good in using try..finally?
Post by: alpine on October 08, 2021, 12:06:17 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.
I doesn't eliminate it. In fact, "try..finally" helps for applying the theory in practice.

The correctness of the algorithm is given with a mathematical proof, it is not expected to be a correctness assertion for a given program which implements the algorithm on a given machine. Usually the proof doesn't take into consideration the particular limitations of the execution environment, such as memory size, speed of execution, external factors, etc.
 
Besides, I doubt the correctness can be proven formally in an imperative languages, excluding some very limited cases.

I have seen naïve developers that runs an automated test cases and then claim that their program is correct, even though it fails spectacularly later. Actually, writing test cases (or pre-/post-conditions) is prone to the same programmer faults as with writing the program itself.

IMO, If some wants to write fail-safe programs, he/she should use both techniques - checking preconditions (zerodiv is the obvious example) and also "try..finally", "try..except" in attempt to extend the algorithm correctness over the real thing.
Title: Re: What is good in using try..finally?
Post by: wp on October 08, 2021, 12:14:20 pm
Now it's a good time to post the change I made in your code which shows how "try-finally" can hide bugs.

I just made one small change in TForm1.Button1Click, now it reads:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   i: Integer;
  4.   x: Double;
  5.  
  6.   m : HMODULE;  { added }
  7.  
  8. begin
  9.   Screen.Cursor := crHourglass;
  10.   try
  11.     m := GetModuleHandle(pchar($7FFE0000));  { added }
  12.  
  13.     for i := 0 to 100 do
  14.       x := 1.0 / sin(x);
  15.   finally
  16.     Screen.Cursor := crDefault;
  17.   end;
  18. end;
  19.  
In the original code, the invalid value of "m" was used but, the corrective actions done in the "finally" didn't solve the problem, on the contrary, it hid it because it wasn't expecting that kind of problem.  The net effect was, the program ran but, the information it showed was obviously incorrect.
I don't understand what you are saying here. "Original code" = my posted code? It did not use any "m"... Which information was incorrect?

In my understanding: If you don't use try-finally the bug you introduced is still there. You can't blame try-finally for this.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 12:27:19 pm
I don't understand what you are saying here. "Original code" = my posted code? It did not use any "m"... Which information was incorrect?
Not your code.  This is a problem I saw in somebody else's code, which I referred to as "the original code".

In my understanding: If you don't use try-finally the bug you introduced is still there. You can't blame try-finally for this.
Yes, it's still there but, the actions taken by the "try-finally" in the original code left the impression that everything was fine when it really wasn't.  Effectively, it hid that bug because the actions taken in the "finally" part had nothing to do with the problems caused by the invalid parameter in GetModuleHandle.

IOW, the common presumption is that whatever goes wrong is taken care of in the "finally" part and we both know that is not the case.  The "try-finally" ends up hiding the bug because the program keeps running as if nothing wrong had happened.


Title: Re: What is good in using try..finally?
Post by: wp on October 08, 2021, 12:34:40 pm
I think I leave here because I cannot (and do not want to) convince you. All was said from my side.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 12:40:22 pm
I think I leave here because I cannot (and do not want to) convince you. All was said from my side.
No problem, that's fine. 
Title: Re: What is good in using try..finally?
Post by: Warfley on October 08, 2021, 01:54:49 pm
and that's how we end up with languages like Java.  For throw away stuff or prototyping something, it's perfectly fine, even handy but, when the goal is to produce a really good program things like Java are a joke.
Manual memory management is bad. When rewriting their CSS eingine Mozilla analysis of the bug reports within the old code and identified 43 total security compromising bugs (link (https://hacks.mozilla.org/2019/02/rewriting-a-browser-component-in-rust/)). Of those 34 where identified as highly critical. 32 of which where related to manual memory management. Mozilla developers are generally speaking not bad developers, they are one of the few companies that have the luxury of being able to hire some of the best developers in the world. Still even the best of the best make a lot of mistakes and most of them are related to manual memory management. (Note that 7 errors where null pointer errors, which can also be completely avoided through language design)

This is why modern languages don't use manual memory management anymore. For this reason Mozilla developed a completely new language Rust, which makes all of these memory issues impossible (without the loss of performance). Other languages today usually use other mechanisms to manage memory automatically. Java or .Net make use of garbage collectors. More lower level languages like C++ (since c++11), Go or Swift make use of reference counting. All of them have their advantages and disadvantages (I won't go into any more detail here, this is a discussion on it's own). But fact is, developers are not able to consistently write bug free code with manual memory management, so the languages need to account for that.

To quote from the article about the change to Rust:
Quote
Due to the overlap between memory safety violations and security-related bugs, we can say that Rust code should result in fewer critical CVEs (Common Vulnerabilities and Exposures). However, even Rust is not foolproof. Developers still need to be aware of correctness bugs and data leakage attacks. Code review, testing, and fuzzing still remain essential for maintaining secure libraries.

Compilers can’t catch every mistake that programmers can make. However, Rust has been designed to remove the burden of memory safety from our shoulders, allowing us to focus on logical correctness and soundness instead.

So no, automatic memory management is not only for prototyping. To the contrary, it always should be used (if possible) in production code, as removes the largest source of errors in programming and makes your applications more reliable.


But I think after all of this fuzz, its save to say that we simply won't agree any time soon. So I will leave it at that. I will concede that the implementation of Exceptions as it stands in Pascal is still lacking and prone to misuse, something that other exception designs (like Java where the function signature must include all exceptions that can be fired, or Haskell where exceptions are part of the return type) do defenetly better. But aside from that I stand at my point that exceptions are generally a good feature
Title: Re: What is good in using try..finally?
Post by: alpine on October 08, 2021, 03:32:23 pm
*snip*
try..finally and try..except are modern tools to handle error, although under the hood they are still if-s and jumps just like any other code. While it helps to automate different things, it also adds an overhead to the code.
Actually, they're setjmp/longjmps and they can (usually do) transfer the execution to very far points in your program.

An immediate conclusions: Do not use them if no error can occur, especially if something is executed multiple times (like a loop running in a billion times). Later I cover the finally bit, what only makes sense if there is something to do finally (typically heap memory or hardware release), while the except bit can be placed higher in the calling hierarchy reducing the overhead significantly.
It is not reducing overhead, rather is for generalizing your error handling. Here it comes "try..finally" which helps you do a proper cleanup into the inner calls before handling the exception.


try..finally
and try..except are if-s and jumps, so they theoretically can be used for other purposes. The general rule is that one should use it only for real exceptions, not for normal process flow. It sounds simple, but far not that easy in real life (especially if one likes this structure). Look at the next example:
Code: Pascal  [Select][+][-]
  1. procedure HireEmployee;
  2.   var
  3.     Age : integer;
  4.   begin
  5.   writeln('How old are you?');
  6.   readln(Age);
  7.   try
  8.     if Age<14 then raise ExceptionChild;
  9.     if Age<18 then raise ExceptionYoung;
  10.     ProcessApplication;
  11.   except
  12.     On E:ExceptionChild do writeln('You are a child, cannot work here');
  13.     On E:ExceptionYoung do writeln('You are too young, you need your parents'' approval to work here');
  14.     end;
  15.   end;
  16.  
It is perfectly working, but abuses the structure and should not be used like this. On the other hand a similar if..raise can be OK in the retirement home age checking. If someone is younger than 18 there then it can be a real programming error (remember Y2K?) and need to be handled as an exception.
It is about what the definition of exception is. Defining a special case in your algorithm as an exception, even if it can be properly handled with if/then is a bad practice, IMHO. You fall into the trap of using exceptions just because you can.

(Funfact: after I wrote this example, I just found C++ tutorial https://www.w3schools.com/cpp/cpp_exceptions.asp (https://www.w3schools.com/cpp/cpp_exceptions.asp) recommending try for just this particular check...)
I hope it is only to illustrate how it can be done with the construct.

*snip*
As per statistics finally is 70X more used than except. Still to me try..except is the more natural use (just like in C++ there is only try..catch).
The prevalence of the finally is because it is a common practice to do this:
Code: Pascal  [Select][+][-]
  1.   L := TStringList.Create;
  2.   try
  3.     // use L
  4.   finally
  5.     L.Free;
  6.   end;

*snip*

Usecase 2 - Access to resources (hardware, network, file, etc.)
Just like in the above case, the error is beyond our control, and if the call can raise exceptions, I would try to catch it as soon as possible.
There is another consideration for acting ASAP when dealing with shared resources: In a multitasking environment it is important to minimize the use of the resource, e.g. to prevent deadlocks. The common rule is when the next resource can't be acquired to release all those previously held. 

*snip*

So far easy. So far I had known it. Now, back to my original post. If I handle the exception then the program execution continues after the except block and I can release all the resources I allocated (memory, hardware) or reset the ones I changed (like the Cursor). Why do I need try..finally and what happens to the exception that caused the problem at the first place. This is what I learnt now.

Usecase 4 - No exception, but multiple exit points
If I have three algorithms to solve a problem, I can do (incorrectly):
Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     Screen.Cursor := crHourglass;
  4.     try
  5.       if Solved1 then exit;
  6.       if Solved2 then exit;
  7.       if Solved3 then exit;
  8.       Writeln('Cannot solve');
  9.     except
  10.       // meaningless code, as no exception is raised (unless in one of the SolvedX, but that is beyond the point now
  11.     end;
  12.   Screen.Cursor := crDefault;
  13.   end;
  14.  
The result is that the Cursor remains crHourglass if the problem is solved. I personally like exit, but I do remember some professional companies explicitly forbid to use it: One method can have only one exit point.
I would allow multiple exits, but then to me exit is exit, so I would not allow exit with finally. That is far too confusing to me, but it might be my old school.
Anyway the try..finally works well in this case.
My humble advice is to use "try..finally" in each case something was done at the beginning and must be reverted at the end.

Usecase 5 - We do not want to handle the exception
This is the second big learning for me.
Actually it is wrong to handle exceptions that occurred in our own code. If we notice something wrong (e.g. an underage employee candidate) and can handle it then it should be handled through normal, old school mechanisms. (I know it is debatable, but this is my takeaway!) We shall only raise an exception if we cannot handle it and want to inform the caller about the failure. So, typically we do not handle the exception raised in our function. Since there is no try..end structure (it is clearly meaningless, this is why!), if we return to the caller after an exception, the code to release the resource is never used.
It is the same if the exception occurs in a function we call and we are unable or unwilling to handle it. The exception goes back to the first try.. level and stops there, but any code in between is never executed. This is when try..finally comes into the picture.
Code: Pascal  [Select][+][-]
  1.   Screen.Cursor := crHourglass;
  2.   try
  3.     if Age<14 then raise ExceptionChild;
  4.     if Age<18 then raise ExceptionYoung;
  5.     ProcessApplication;
  6.   finally
  7.     Screen.Cursor := crDefault;
  8.     end;
  9.  
The exceptions are sent to the caller, signing that we cannot process the job application, but still the Cursor is reset.
This is especially true when resource allocation was performed at earlier stages, they should be de-allocated before the execution is transferred to the caller.   

One thing that bothered me, still. Why is it 70X more frequent to use try..finally than try..except?
try..finally is logically used a lot, especially in OOP, where objects are created in the Heap and need to be released. In old school OOP even this was not necessarily true, as objects could be in the stack and released automatically once the function returned. With classes it changed and need to be released. As most components we use today are classes, it makes memory leak prevention a priority.
But why exceptions are not handled close to the error, i.e. many-many times in our codes? One answer is given above, i.e. if it can be solved, it is not an exception. The other answer is that if an exception is handled, from that moment on, it does not exist and the program runs happily (i.e. unaware) until it crashes. So, it is better to let the exception raise as high as the point where it can really be handled efficiently. Imagine something like:
Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.     try
  4.       c := a/b;
  5.     except
  6.       writeln('Div/0');
  7.     end;
  8.   end;
  9. procedure b;
  10.   begin
  11.     try
  12.       c := a/b;
  13.     except
  14.       writeln('Div/0');
  15.     end;
  16.   end;
  17. // and so on
  18. procedure z;
  19.   begin
  20.     try
  21.       c := a/b;
  22.     except
  23.       writeln('Div/0');
  24.     end;
  25.   end;
  26. procedure All;
  27.   begin
  28.   a;
  29.   b;
  30.   // and so on
  31.   z;
  32.   end;

vs.

Code: Pascal  [Select][+][-]
  1. procedure a;
  2.   begin
  3.   c := a/b;
  4.   end;
  5. procedure b;
  6.   begin
  7.   c := a/b;
  8.   end;
  9. // and so on
  10. procedure z;
  11.   begin
  12.   c := a/b;
  13.   end;
  14. procedure All;
  15.   begin
  16.     try
  17.       a;
  18.       b;
  19.       // and so on
  20.       z;
  21.     except
  22.       writeln('Div/0');
  23.     end;
  24.   end;
Not only the first is much longer having all the try..except blocks, but also All will call a, b, .. z even if the first one fails, because a hides its error. Maybe later in the program it creates a much bigger problem (e.g. DB corruption). The second approach stops the whole processing, if any of the a, b, .. z. fails.
These two explain why try..finally is frequent and try..except is rare giving a surprising ratio.
Here, the key words are "it stops the whole processing". The exceptions mechanism (when used wisely) can spare you a lot of "if/then/else"  by cutting the code that is meaningless to execute after the error occurred.

And my last wondering, whether try..except..finally would be needed or not.
Well, as said, most of the exception are not handled so try..finally is enough. If the exceptions are handled the final activities can go after the try..except..end block. So, the only times when both except and finally can be necessary is when we want to handle exceptions and also we have multiple non-exception exit points or when we only want to handle some of the exceptions, but not all.
The first is clearly a bad programming practice to me. I already mentioned the danger of using exit, but if we use it and also want to use exception handling, it is very important to know whether the final activity is needed in all cases, or only if there is an early exit or only if there is an exception. A combined try..except..finally would be unclear not talking about the possibility of allowing try..except..finally and try..finally..except. I think it would confuse everyone. So, I agree that even if one wants to use exit and exception handling at the same time, using of nested try.. blocks is the right approach.
The second is also a bit controversial to me. Difficult to imagine a situation, where I handle some of the exceptions raised by the functions I call, but also either do not handle some exceptions received (i.e. let it pass by me) or raise my own ones, and at the same time I still also want to use a finally block. If there is such a rare case, I would agree to use two nested try blocks, making it also clear what is executed when and in what sequence.
I'm not sure I fully understand that, but maybe, if you accept that "try..finally" is simply a mechanism for a proper clean-up and "try..except/raise" is another, unrelated one, for dealing with exceptions, you'll get a more clear picture.

BTW,I wouldn't want to confuse your brain with even more interesting combinations like nesting into the except..end portion:
Code: Pascal  [Select][+][-]
  1.   // your wondering
  2.   try try
  3.     // ...
  4.   except
  5.     // ...
  6.   finally
  7.     // ...
  8.   end end;
  9.  
  10.   // your wondering?
  11.   try try
  12.     // ...
  13.   finally
  14.     // ...
  15.   except
  16.     // ...
  17.   end end;
  18.  
  19.   // double fault
  20.   try
  21.     // ...
  22.   except try
  23.     // ...
  24.   except
  25.     // ...
  26.   end end;
  27.  
  28.   // cleanup only on exception
  29.   try
  30.     // ...
  31.   except try
  32.     // ...
  33.   finally
  34.     // ...
  35.   end end;
  36.  
  37.   // exception handling on cleanup
  38.   try
  39.     // ...
  40.   finally try
  41.     // ...
  42.   except
  43.     // ...
  44.   end end;
  45.  
  46.   // etc.
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 03:52:43 pm
I don't like camping on yet another interminable philosophical debate, particularly since I don't think the forum has a "withdraw from this thread" button.

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.

Have you studied the original UNIX source, and seen the hoops through which the authors had to jump to handle things like context switching? Well, neither have I but there's plenty of quotes from the Lions Book along the lines of

Code: C  [Select][+][-]
  1. /*
  2.          * If the new process paused because it was
  3.          * swapped out, set the stack level to the last call
  4.          * to savu(u_ssav).  This means that the return
  5.          * which is executed immediately after the call to aretu
  6.          * actually returns from the last routine which did
  7.          * the savu.
  8.          *
  9.          * You are not expected to understand this.
  10.          */
  11.         if(rp->p_flag&SSWAP) {
  12.                 rp->p_flag =& ~SSWAP;
  13.                 aretu(u.u_ssav);
  14.         }
  15.  

Over the last 70 years there has been a gradual progression where people "skilled in the art" have recognised behavioural idioms in code and abstracted them into well-understood and thoroughly-debugged facilities in the languages, libraries and OSes they're using.

For example, code has been encapsulated- with widely-consistent scoping and visibility rules- into ALGOL-style blocks and functions/procedures. Control flow has been abstracted into threads (preemptive or otherwise). Resource ownership has been abstracted into processes (with naming variations, particularly on "big iron"). Subprograms have been abstracted into modules and libraries, with an increasing tendency towards robust type checking.

And in the spirit of that, GOTO was abstracted: first to a setjmp/longjmp convention, then to start/finally, and as a variant of that to try/except (with various actual names).

The anointed survivors of the GOTO lineage, start/finally and try/except, have somewhat different behaviour when they interact with thread/process state: simplistically, start/finally is deterministic and interacts only with the current stack while try/except might require far more work to unwind and might interact with the current threads etc. in a far more complex fashion. But both of those hide a great deal of complexity from their users: complexity which the early writers of OSes etc. had to address with no significant language assistance.

So /that's/ why current workers are better off using current abstractions: start/finally and try/except.

Now, going back to OP's question: a number of people have pointed out that start/finally and try/except have somewhat different behaviour. However my reading of the discussion so far hasn't noted anybody pointing out that it is increasingly common for the underlying OS to be deeply entwined with try/except handling: which is to be expected, since this is after all the same mechanism which is used to catch hardware-initiated traps (divide by zero, alignment errors and so on).

So to summarise: a smart programmer is at liberty to avoid start/finally (or whatever it is called in his environment), but the price is significant extra complexity in the OS or whatever he's writing: and I suspect I've spent more time in vintage OSes than most. And a programmer is free to munge try/except to to the job of start/finally, but doing so is /not/ smart because of the extra runtime overhead that it normally implies.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 05:08:51 pm
Manual memory management is bad.
I was going to click the "withdraw from thread" button MarkMLI mentioned but, I cannot let this one go.

Manual memory management is not bad, it's actually quite good when it's well designed.  What's bad, are programmers at manual memory management. That's where the problem is and, slapping memory management crutches into compilers causes programmers never to become any better at it. 

That's it.  I'm done with this.  goto has been renamed "try-except", after that Kafkan transformation, it  has gone from ostracized to esteemed citizen.   Gotta hand it to the marketing people, they know how to make anything look good.  It's all in the packaging.
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 08, 2021, 05:09:48 pm
GOTO is just a jump. Get real y'all. This annoys me a bit (a lot).

(More on subject: take care of automatic try/finally, do not duplicate)

And yes, I adore try/finally even above try/except (which you should not use unless necessary).
The two are imho unrelated......
https://www.freepascal.org/docs-html/ref/refch17.html
Also note that according to the documentation EXIT will still execute the finally part. If not, that is a bug,

Again, reading manuals is such a gift.... >:D >:D >:D Oh, it is a Friday, so  ;D :D :)

Silly bunch
"Note that an Exit statement enclosed by a try .. finally block, will still execute the finally block. Reusing the previous example:"
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 05:23:21 pm
That's it.  I'm done with this.  goto has been renamed "try-except", after that Kafkan transformation, it  has gone from ostracized to esteemed citizen.

Hardly: it's got the social standing of somebody who washes corpses for a living.

Everybody- without exception- says "do not use this unless you really have to". Virtually all documentation cautions against using raise (or whatever a particular environment calls it) for routine control flow.

I confess: I use GOTO on occasion. I use setjmp/longjmp on occasion. I use try/except on occasion. I use start/finally on occasion (and I /so/ wish that Object Pascal hadn't overloaded try for that structure) but I am very careful to annotate exit etc. in that context. But it's very much horses for courses, and it's appropriate for Dijkstra to have the last word:

Quote
Please don't fall into the trap of believing that I am terribly dogmatical about [the goto statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 08, 2021, 05:25:58 pm
Indeed. A jump is a jump, whatever you look at it. And that seems to be no exception pun intended,  :P
People should get more understanding of the ASM output the compiler generates: A jump is  a jump is a GOTO and a jump... :o. A GOTO is a jump..... <sigh, boring>

BTW: GOTO is not evil, just for bad programmers who do not understand it. Read the above.
The most problems I see is how to use labels..... Now that is an interesting subject.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 06:10:19 pm
Hardly: it's got the social standing of somebody who washes corpses for a living.

Everybody- without exception- says "do not use this unless you really have to". Virtually all documentation cautions against using raise (or whatever a particular environment calls it) for routine control flow.
OOP programmers are basically forced to use try-except because it seems the favored way in OOP to report an error is to raise an exception which has to be caught by an exception handler (try/except.)

I don't know what the documentation says but, the reality is pretty close to try-except for OOP breakfast, try-except for OOP lunch and, try-except for OOP dinner.


Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 06:22:19 pm
OOP programmers are basically forced to use try-except because it seems the favored way in OOP to report an error is to raise an exception which has to be caught by an exception handler (try/except.)
[/quote]

I don't see why that should be anything to do with OOP, /except/ for the case where a constructor returns an instance (and even then the caller could quite easily check whether it's being fed a null pointer).

I would throw in at this point that I'm not entirely happy about the OOP fiction that procedures/functions are actually "methods" and that they're inevitably invoked by sending "messages" around: I'm really not sure to what extent that was even true for Smalltalk and Simula.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 08, 2021, 06:24:53 pm
Everybody- without exception- says "do not use this unless you really have to".
It is simply a sign of incompetence. When used indiscriminately.

There is a vail of that amongst this discussion...
Notably the predictability: exception are there for the UN-predicted, not to catch the predictable. BTW that goes for any language, not only Pascal.
It is frankly a nightmare to educate these people. Fire them after two mistakes.
(I am pensionado, a bit, so you won't get fired...)

And nobody is forced to use exceptions... Same reason to loose your job....
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 06:39:38 pm
I don't see why that should be anything to do with OOP, /except/ for the case where a constructor returns an instance (and even then the caller could quite easily check whether it's being fed a null pointer).
It has to do with OOP because there are constructions in OOP that don't provide a way for the programmer to return an error code (e.g, as a function result) forcing the programmer to raise an exception to report any error.

That said, I am under the impression that the above applies mostly, if not exclusively, to the Pascal OOP implementation.
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 06:56:32 pm
It has to do with OOP because there are constructions in OOP that don't provide a way for the programmer to return an error code (e.g, as a function result) forcing the programmer to raise an exception to report any error.

Such as? But as you concede: it's important to distinguish between the OOP concept, the Object Pascal implementation, and the LCL (etc.) which is built on top of the language implementation.

I don't think that Smalltalk (as originally popularised, i.e. the -80 variant) had exceptions, unless you consider the "do not understand" response to an unimplemented "message" to be one.

I hope OP will excuse this subthread, but I think "are there situations in which try/except has to be used?" is probably germane to his question.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 08, 2021, 07:00:37 pm
That said, I am under the impression that the above applies mostly, if not exclusively, to the Pascal OOP implementation.
What makes you think that? The paradigm is the same across languages and certainly not just Pascal.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 08, 2021, 07:19:33 pm
@MarkMLI, @Thaddy

Pascal has properties.  If something goes wrong in a setter, I am under the impression that the only option to notify the caller of a problem in a setter is to raise an exception.

Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 07:28:21 pm
Pascal has properties.  If something goes wrong in a setter, I am under the impression that the only option to notify the caller of a problem in a setter is to raise an exception.

Yes, good point... although it would potentially be possible to augment the returned type with a special "something's wrong" value, or to poll an error flag.

I've got reservations about the way that properties hide the form of the implementer, which makes debugging more difficult. But that's a very old debate, and their sheer convenience as an abstraction seems to have overruled all objections to their syntax.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: alpine on October 08, 2021, 07:30:50 pm
@MarkMLI, @Thaddy

Pascal has properties.  If something goes wrong in a setter, I am under the impression that the only option to notify the caller of a problem in a setter is to raise an exception.

Is it all that fuss about properties actually? How they can be confused with OOP?
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 08, 2021, 08:02:11 pm
@MarkMLI, @Thaddy

Pascal has properties.  If something goes wrong in a setter, I am under the impression that the only option to notify the caller of a problem in a setter is to raise an exception.

Is it all that fuss about properties actually? How they can be confused with OOP?
I did not write up *anything* about properties. Just to stand corrected,  >:D
Title: Re: What is good in using try..finally?
Post by: Warfley on October 08, 2021, 08:05:10 pm
Manual memory management is not bad, it's actually quite good when it's well designed.  What's bad, are programmers at manual memory management. That's where the problem is and, slapping memory management crutches into compilers causes programmers never to become any better at it. 
Again this sentiment that programmers should just get better at programming. If even the programmers at Mozilla, a company with highly competative salaries and a really good reputation, which can basically hand pick the best of the best developers in their field, run into these problems, simply telling the programmers to get better ain't gonna cut it.
Automatic memory management is needed because it has been shown time and time again that even the best programmers aren't able to make manual memory management working bug free.

Do you have the same sentiment everywhere? What you can't run 100km at 130kmh, well you shouldn't use a car, you should just try to run faster. It simply doesn't wor this way. When we hit a problem, we simply create tools that solve that problem for us. Thats what tools are for. Thats what makes us humans so successful

There have multiple solutions been proposed to that problem (compile time ownership and borrowing in rust, Garbace collection ala java or reference counting), sure not every solution fits every situation (e.g. does the rust concept not have any runtime overhead but is therefore rather restictive, while a GC is the most flexible but has the most overhead) but for pretty much every situation there are solutions that are feasable. Manual memory management is bad. It has been removed or sidelined from all major languages and it has proven to be an improvement.

Indeed. A jump is a jump, whatever you look at it. And that seems to be no exception pun intended,  :P
People should get more understanding of the ASM output the compiler generates: A jump is  a jump is a GOTO and a jump... :o. A GOTO is a jump..... <sigh, boring>

No a jump is not a jump. There are many different kinds of jumps each with their own restrictions and use cases. An If is a jump downwards within the same scope with a condition, a repeat is a jump within the same scope with a condition. Break and Continue are jumps to either the beginning or end of a loop. Goto is a jump within the same context but accross scopes in any direction. Longjmp is a jump to any location that was already visited previously. An exception is a jump down the stack multiple stack frames. A function call is a jump up the stack with a return being a jump down 1 stack frame.
A "jump is a jump" as much as a fruit is a fruit. Try making apple juice from a banana. Just because all these things share some characteristics doesn't mean they are to be treated identically. Each form of jump has it's pros and cons. You can't just replace a function call with goto, or goto with an exceptions. That simply doesn't work.

The problem with Goto is that it has very little restrictions, which makes it prone to misuse. The idea behind things like loops with continue and break instead of goto or Exceptions instead of longjmp is that these "new" constructs are more restrictive. Rather than having one very generalized jump that can do everything and can be therefore easiely misused is to rather have many very specialized ones, that can only be used with some constraints (e.g. break only in a loop) and make misusing them thereby harder.
Title: Re: What is good in using try..finally?
Post by: alpine on October 08, 2021, 08:09:08 pm
@MarkMLI, @Thaddy

Pascal has properties.  If something goes wrong in a setter, I am under the impression that the only option to notify the caller of a problem in a setter is to raise an exception.

Is it all that fuss about properties actually? How they can be confused with OOP?
I did not write up *anything* about properties. Just to stand corrected,  >:D
Nobody did, at least until reply #46.  :o
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 08, 2021, 08:23:38 pm
Nobody did, at least until reply #46.  :o

Yes, I agree. So basically that is an Object Pascal feature which mandates or at least encourages use of exceptions, rather than an OOP one.

I should have spotted that, since I've been banging the drum about language design being distinct from language implementation etc. for 30+ years.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 04:34:02 am
Maybe I'm wrong but, it seems to me that properties are part of the OOP paradigm in Pascal, therefore, if raising an exception from a property is necessary to indicate an error occurred to the caller, that's a characteristic of OOP and, Pascal's implementation of OOP.

Also, for the record, I qualified my statement about OOP with the following:
That said, I am under the impression that the above applies mostly, if not exclusively, to the Pascal OOP implementation.
I may be wrong again but, it seems to me that OOP programmers in this forum are using Pascal's implementation of OOP, including properties which means, a lot more exceptions than are necessary.

Therefore, it is completely appropriate to associate the common use of exceptions with Pascal's implementation of OOP.



Again this sentiment that programmers should just get better at programming.
I believe I share that sentiment with a great number of people because when a company is looking for a programmer, they very commonly ask for experience (I "suspect" that's because they want a programmer who has - hopefully - spent some time getting better at programming)

If even the programmers at Mozilla, a company with highly competative salaries and a really good reputation, which can basically hand pick the best of the best developers in their field, run into these problems, simply telling the programmers to get better ain't gonna cut it.
First, my hat off to the programmers at Mozilla.  Writing something like Firefox is no picnic.  It definitely takes a lot of dedication and talent.  That said, it doesn't mean they are always right.  They are not, they are human, they make mistakes and they are also influenced by factors that have nothing to do with programming.

So far, I haven't seen any implementation of automatic memory management that I'd want to use.  Honestly, without bragging, I can do _way_ better every time.

Automatic memory management is needed because it has been shown time and time again that even the best programmers aren't able to make manual memory management working bug free.
I'd normally say that I would take such a statement with a grain of salt but, in this case, I think I'm going to have to work out a deal with the state of Utah.

Do you have the same sentiment everywhere? What you can't run 100km at 130kmh, well you shouldn't use a car, you should just try to run faster. It simply doesn't wor this way. When we hit a problem, we simply create tools that solve that problem for us. Thats what tools are for. Thats what makes us humans so successful
I have the same sentiment about anything someone chooses to do as a profession.  IOW, I don't expect Mary Housewife to become a race car driver because she drives her car to the grocery store.  That said, I still expect her not to run into people, trees, fire hydrants and, I also expect her to stop at red lights (among other things.)   Maybe I'm a demanding kind of guy but, if she cannot consistently accomplish those things, she will  probably (and hopefully) not be allowed to drive a car (something to be thankful for)

Automatic memory management is a bit like a TV dinner.  5 minute in the microwave and whatever is there can (hopefully) be used to fill your stomach.  Chef Boyardee memory management.


Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 09:55:58 am
Maybe I'm wrong but, it seems to me that properties are part of the OOP paradigm in Pascal, therefore, if raising an exception from a property is necessary to indicate an error occurred to the caller, that's a characteristic of OOP and, Pascal's implementation of OOP.

I'm sorry, but while I don't disagree with your specific points the logic that you use to get to them is sufficiently flaky that I really do have to comment on it.

"properties are part of the OOP paradigm in Pascal": OK, you're saying there that properties are a part of Pascal, but are implicitly admitting that other flavours of OOP do or at least could exist without them.

"raising an exception from a property (is) a characteristic of OOP"

No, that's wrong. You've already said that properties are part of Pascal and that other flavours of OOP might not use them, so your statements are contradictory.

Again, I don't necessarily disagree with you. But using bad logic is never good practice since it allows an opponent- should there be one- to attack your position.

My recollection is that you made the blanket statement somewhat earlier in the thread that exceptions were part of OOP, therefore if exceptions are a bad idea then so is OOP. Just about everybody agrees that overuse of exceptions is a problem, which is an incentive to avoid their use where possible, which is one of the points being made to OP when he asks about try/finally which is somewhat better behaved.

But OOP in the general case is /not/ tainted by that since exceptions are an Object Pascal thing. And even Object Pascal is not necessarily beyond redemption, since heavy use of exceptions appears to be mandated by the specific way that people have chosen to use properties with active getters/setters heavily: and while those are undoubtedly useful it would again be faulty logic to insist that the presence of active getters/setters in some extensions (i.e. the LCL etc.) condemns Object Pascal in its entirety, hence condemns OOP in its entirety.

Now we could of course take the Ada approach, and mandate that there must be nothing in the language which is unsafe, hence that an attempted implementation which highlights an unsafe consequence of some sloppy bit of the language definition condemns the language in its entirety. I'm not necessarily against that, BUT in the current case nobody has demanded that we adopt that paradigm.

So in summary: exceptions are a Bad Thing in excess, but their use is demanded by heavy use of active getters and setters in the LCL and elsewhere. That is, arguably, a poor design choice in the LCL, and that could possibly be argued as a point against Object Pascal, but since Object Pascal is only one implementation of the OOP paradigm it can hardly be argued as outright condemnation of OOP itself.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Seenkao on October 09, 2021, 10:21:43 am
Мне пришлось отказаться от использования try..finally. По сути, они не производят исключения, ошибка всё же происходит. А когда мне надо разрабатывать программу, и я натыкаюсь на исключение, то я не могу гарантировать, что готовая программа не вылетит в данном месте.
Мне приходится производить исключения самому, и "вылавливать" эти исключения до того, как они появятся в рабочем коде. Это долгая рутинная работа. Но и try...finally не уберегут меня от этой рутинной работы. Но, если мы на низком уровне произведём все проверки, то на более высоком уровне, мы столкнёмся с меньшим количеством ошибок.
Так же, я стараюсь вводить логирование в такие места. И включать/выключать эти логи в данных местах.

yandex translate:
I had to give up using try..finally. In fact, they do not produce exceptions, the error still occurs. And when I need to develop a program, and I stumble upon an exception, then I cannot guarantee that the finished program will not crash in this place.
I have to make exceptions myself, and "catch" these exceptions before they appear in the working code. It's a long routine job. But also (try...finally) will not save me from this routine work. But if we perform all the checks at a low level, then at a higher level, we will encounter fewer errors.
Also, I try to enter logging in such places. And enable/disable these logs in these places.

GOTO is just a jump. Get real y'all. This annoys me a bit (a lot).
GoTo - это не совсем прыжок. Это условный/безусловный переход из одной части программы, в другую. Каждый программист должен понимать, что GoTo - это неотъемлемая часть программирования. Хороший программист будет управлять программой с помощью GoTo достаточно неплохо. Но новичкам лучше не использовать его (знать нужно).
А так GoTo никуда не делся из программ, без него ваша программа (по большей части) и работать не будет. Где вы видели программу, которая работала только на вызовах процедур?  :)

yandex translate:
GoTo is not exactly a leap. This is a conditional /unconditional transition from one part of the program to another. Every programmer should understand that GoTo is an integral part of programming. A good programmer will manage the program using GoTo quite well. But it's better for beginners not to use it (you need to know).
And so "Goto" has not disappeared from the program, without it your program (for the most part) will not work. Where have you seen a program that only worked on procedure calls? :)
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 10:43:20 am
Where have you seen a program that only worked on procedure calls? :)

Anything that uses strict functional programming. In fact proponents go to a great deal of trouble to avoid conditionals including what we'd consider to be grossly-excessive overuse of transcendental functions since they have traditionally argued that that makes programs more amenable to parallelisation (i.e. strict SIMD).

Now I grant that that answer isn't strictly relevant to Object Pascal, but you made an unqualified statement and asked for a response. However there's a lot of abstractions in OP that you don't have in strict functional programming (and a lot in OP that you don't get in strict procedural programming, and so on) so I would urge you to take on board the points- /valid/ points IMO- made by Thaddy and others.

And the next time you have problems using try/finally etc. I suggest asking for help sorting out what's wrong.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 10:46:20 am
I'm sorry, but while I don't disagree with your specific points the logic that you use to get to them is sufficiently flaky that I really do have to comment on it.
I'll quote what I said again:
It has to do with OOP because there are constructions in OOP that don't provide a way for the programmer to return an error code (e.g, as a function result) forcing the programmer to raise an exception to report any error.

That said, I am under the impression that the above applies mostly, if not exclusively, to the Pascal OOP implementation.
I made it a point to acknowledge that this may be a problem specific to the Pascal OOP  implementation.

There are lots of problems in OOP regardless of language but, I don't know if other OOP languages force the use of exceptions to report errors and in what cases, if any.  I do know that the Pascal OOP implementation does.

Also and, very important, since we are in a Pascal forum, it seems reasonable to me to presume that our concern is mostly, if not entirely, with OOP in Pascal.

There are a fair number of languages out there that use their own "flavor" of the OOP paradigm.  That would even make it difficult to set clear boundaries as to what is included and not included in OOP.

The one thing they all have in common is the use of function tables to implement "methods". Beyond that, it seems everything is up for grabs.

I associate properties with OOP because no non-OOP language that I know of has them.

"properties are part of the OOP paradigm in Pascal": OK, you're saying there that properties are a part of Pascal, but are implicitly admitting that other flavours of OOP do or at least could exist without them.
Absolutely.


"raising an exception from a property (is) a characteristic of OOP"

No, that's wrong. You've already said that properties are part of Pascal and that other flavours of OOP might not use them, so your statements are contradictory.
I don't see it that way.  I think that any language that implements properties the way they are implemented in Pascal would end up forcing the use of exceptions on programmers in order to indicate an error condition and, since properties seem to be a feature that is only available in OOP languages, it seems very reasonable and logical to me to consider them a part of OOP.  A part that some languages implement and others don't but, still a part of OOP.

My recollection is that you made the blanket statement somewhat earlier in the thread that exceptions were part of OOP, therefore if exceptions are a bad idea then so is OOP. Just about everybody agrees that overuse of exceptions is a problem, which is an incentive to avoid their use where possible, which is one of the points being made to OP when he asks about try/finally which is somewhat better behaved.
Exceptions are definitely not a part of OOP.  Exceptions are available in plain C and there is no OOP there but, OOP and, very specifically, the Pascal implementation of OOP makes exceptions _necessary_ in order to make some of its features (e.g, setters) being useful.  That is not the case in C.  It is rare to need an exception handler in C because there is not C feature that requires using them - unlike setters in OOP Pascal.

But OOP in the general case is /not/ tainted by that since exceptions are an Object Pascal thing.
Honestly, at this point, I think it's difficult to define what is and isn't part of OOP but, as previously stated, properties are part of OOP Pascal, therefore any negative side effects they may have on programming reflects on OOP generally and very specifically on its Pascal implementation.

So in summary: exceptions are a Bad Thing in excess, but their use is demanded by heavy use of active getters and setters in the LCL and elsewhere. That is, arguably, a poor design choice in the LCL, and that could possibly be argued as a point against Object Pascal, but since Object Pascal is only one implementation of the OOP paradigm it can hardly be argued as outright condemnation of OOP itself.
Is it really simply a poor design choice ?... it's definitely a poor design choice but it is also one that is encouraged by the language in various ways, the most common one is the apparently limitless indulgence in syntactic sugar that many OOP programmers seem to be addicted to.

Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 11:19:27 am
properties are part of OOP Pascal, therefore any negative side effects they may have on programming reflects on OOP generally and very specifically on its Pascal implementation.

Sorry, that's still bad logic.

I'd suggest this: Object Pascal has OOP facilities, which it extends in various ways.

One of the extensions is to support properties, which are there in an attempt to control access.

One of the features of properties is that they can have active getters/setters, rather than being a passive public shortcut to a private field.

The definition of Object Pascal permits an active getter/setter to propagate an unhandled error via a property (which "looks" like a field/variable) to whatever is accessing it, where it can only be caught as an exception.

Since exceptions are widely criticised as a Bad Thing, that permission could be regarded as a flaw in the language definition.

It could be argued that the LCL's heavy exploitation of that flaw is in itself a design failure. However it's arguable whether that taints any particular language implementation (FPC etc.) and it definitely doesn't taint OOP in its entirety.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Seenkao on October 09, 2021, 11:31:33 am
Anything that uses strict functional programming. In fact proponents go to a great deal of trouble to avoid conditionals including what we'd consider to be grossly-excessive overuse of transcendental functions since they have traditionally argued that that makes programs more amenable to parallelisation (i.e. strict SIMD).

Now I grant that that answer isn't strictly relevant to Object Pascal, but you made an unqualified statement and asked for a response. However there's a lot of abstractions in OP that you don't have in strict functional programming (and a lot in OP that you don't get in strict procedural programming, and so on) so I would urge you to take on board the points- /valid/ points IMO- made by Thaddy and others.

And the next time you have problems using try/finally etc. I suggest asking for help sorting out what's wrong.

MarkMLl
Извиняюсь, но это относится к любому программированию! Будь то функциональное или ООП. Не стоит забывать, что любое ООП без особых проблем заменяется функциональным. А вот наоборот не получится полностью (разве что эмулировать). Почему все забывают, что функциональное программирование - это основа, а ООП - это уже одна из довольно неплохих наработок (которую зачастую лепят где нужно и где не нужно).
Маловероятно что я буду дальше использовать try...exception/try..finally. Я занимаюсь более низкоуровневым программированием. И многие варианты уже решены с оповещением пользователя/программиста. Как визуально, так и с использованием логов.
Я не говорил, что try..finally - это плохо. Большинству это нужно! :)

yandex translate:
I'm sorry, but this applies to any programming! Whether functional or OOP. Do not forget that any OOP is replaced by a functional one without any problems. But on the contrary, it will not work completely (except to emulate). Why does everyone forget that functional programming is the foundation, and OOP is already one of the pretty good developments (which is often molded where necessary and where not necessary).
It is unlikely that I will continue to use try...exception/try..finally. I'm doing more low-level programming. And many options have already been solved with the notification of the user/programmer. Both visually and using logs.
I didn't say that try..finally is bad. Most people need it! :)
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 11:44:34 am
However it's arguable whether that taints any particular language implementation (FPC etc.) and it definitely doesn't taint OOP in its entirety.
IMO, since Pascal without OOP cannot have properties, it taints the Pascal implementation of OOP. 
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 11:48:19 am
However it's arguable whether that taints any particular language implementation (FPC etc.) and it definitely doesn't taint OOP in its entirety.
IMO, since Pascal without OOP cannot have properties, it taints the Pascal implementation of OOP.

Your opinion's fine, your logic isn't :-)

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Seenkao on October 09, 2021, 11:49:59 am
IMO, since Pascal without OOP cannot have properties, it taints the Pascal implementation of OOP.
Не совсем понимаю. Почему не может? Можно всё сделать самому, это немного другое, но возможно всё.

yandex translate:
I don't quite understand. Why can't it? You can do everything yourself, it's a little different, but everything is possible.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 11:58:32 am
Your opinion's fine, your logic isn't :-)
I see.  Logic and, just simple observation, sees that there is a worm (properties) in the apple (OOP.)  I'll pass on the apple pie. :-)

I don't quite understand. Why can't it? You can do everything yourself, it's a little different, but everything is possible.
It wouldn't have the same syntax.  Procedurally, it would be a function with a parameter (hopefully not a procedure that has to raise an exception to notify the caller that an error occurred.)
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 12:02:12 pm
yandex translate:
I don't quite understand. Why can't it? You can do everything yourself, it's a little different, but everything is possible.

OK, example to support that: a unit can have properties which allow variable-like access to a getter/setter or to a global variable.

A unit can't be instantiated, therefore it's not possible to argue that the presence of units implies OOP.

Therefore the mere presence of properties doesn't imply OOP.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 12:04:32 pm
I see.  Logic and, just simple observation, sees that there is a worm (properties) in the apple (OOP.)  I'll pass on the apple pie. :-)

Rubbish. Your statement- that because there's a flaw in the definition or implementation of Object Pascal then OOP is tainted- would imply that because you saw a worm in one apple you'd never eat anything again.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 12:18:57 pm
Rubbish. Your statement- that because there's a flaw in the definition or implementation of Object Pascal then OOP is tainted- would imply that because you saw a worm in one apple you'd never eat anything again.
Now, that's a creative piece of "logic" there.  The logical conclusion is, worms eat apples and I don't eat apples with worms.

A unit can't be instantiated, therefore it's not possible to argue that the presence of units implies OOP.
That's true but, units existed in Pascal before any OOP features were added to it.  That factually proves that units are not associated with OOP.

Therefore the mere presence of properties doesn't imply OOP.
Could you please point to a Pascal compiler that supports properties but not OOP ?  just in case, not limited to Windows, any Pascal compiler ever written for any architecture is acceptable as an example.

Take your time, I promise I'm not holding my breath :)

Title: Re: What is good in using try..finally?
Post by: Seenkao on October 09, 2021, 12:32:28 pm
OK, example to support that: a unit can have properties which allow variable-like access to a getter/setter or to a global variable.

A unit can't be instantiated, therefore it's not possible to argue that the presence of units implies OOP.

Therefore the mere presence of properties doesn't imply OOP.

MarkMLl
По вашим словам, я делаю вывод, что вы "заблудились" в ООП? Вы не прочитали изначально мой пост выше? Функциональное программирование - это основы. На основах можно сделать всё! Абсолютно всё! Можно тот же ООП со всеми свойствами и многими премудростями сделать заново. ООП и основана на функциональном программировании, но ни как не наоборот.
Можно создать объект, класс, свойства для них и многое другое, посредством функционального программирования. Кто запрещает это сделать?

Тут надо было меня поправить, видимо я некорректный вопрос задал. Надо было задавать вопрос: кто мешает создать объект и свойство для данного объекта посредством функционального программирования.

Но и по сути, можно создавать свойства на "пустом месте". Создаём запись и в ней создаём свойство... бред конечно, но можно. :)

yandex translate:
According to you, I conclude that you are "lost" in the OOP? Did you not initially read my post above? Functional programming is the basics. You can do everything on the basics! Absolutely everything! You can do the same OOP with all the properties and many tricks again. OOP is based on functional programming, but not vice versa.
You can create an object, a class, properties for them, and much more, through functional programming. Who forbids you to do this?

Here it was necessary to correct me, apparently I asked an incorrect question. It was necessary to ask the question: who prevents the creation of an object and a property for this object through functional programming.

But in fact, you can create properties from scratch. Create a record and create a property in it... nonsense of course, but you can. :)

440bx, я понял вашу мысль. )))
440bx, I get your point.)))
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 12:48:07 pm
According to you, I conclude that you are "lost" in the OOP? Did you not initially read my post above?

Yes, and I'm agreeing with you you twp!

MarkMLl
Title: Re: What is good in using try..finally?
Post by: alpine on October 09, 2021, 01:24:46 pm
@Seenkao,
Can you clarify please, what do you mean under the term "functional programming"? Lambda calculus? Or actually, you mean "procedural programming" which in turn is derivation of "imperative programming"?

(functional programming ≠ imperative programming)
Title: Re: What is good in using try..finally?
Post by: Seenkao on October 09, 2021, 01:48:40 pm
@Seenkao,
Can you clarify please, what do you mean under the term "functional programming"? Lambda calculus? Or actually, you mean "procedural programming" which in turn is derivation of "imperative programming"?

(functional programming ≠ imperative programming)
Благодарю. Да, вы правы, тут я в очередной раз "в своих мыслях", и немного в другую степь ушёл. Я про процедурное программирование, путаю периодически. Хотя большей частью это всё связано.

yandex translate:
Thanks. Yes, you are right, here I am again "in my thoughts", and I went to a slightly different steppe. I'm talking about procedural programming, I get confused from time to time. Although for the most part all this is interconnected.

Yes, and I'm agreeing with you you twp!
Что такое "TWP"? А то у меня переводчик не очень хорошим словом обзывает... ))) (но если это правильный перевод, то успехов вам MarkMLl)
yandex translate:
What is "TWP"? And then my translator does not call me a very good word ...)))  (but if this is the correct translation, then good luck to you MarkMLl)
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 02:00:53 pm
What is "TWP"? And then my translator does not call me a very good word ...)))  (but if this is the correct translation, then good luck to you MarkMLl)

You'll need a Welsh to Russian dictionary. And it's not particularly rude :-)

MarkMLl
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 02:20:48 pm
Now, that's a creative piece of "logic" there.  The logical conclusion is, worms eat apples and I don't eat apples with worms.

It's exactly the logic that you're using. I agree that what you're trying to say is that you don't like supplementary protein in your desserts but your "much code written using Object Pascal overuses exceptions therefore OOP is flawed" is a vastly excessive generalisation.

Quote
That's true but, units existed in Pascal before any OOP features were added to it.  That factually proves that units are not associated with OOP.

Agreed, and that's adequate for this discussion. But for completeness I'd warn that the situation with Object Pascal's predecessors such as Edison might not have been so clear cut.

Quote
Could you please point to a Pascal compiler that supports properties but not OOP ?  just in case, not limited to Windows, any Pascal compiler ever written for any architecture is acceptable as an example.

I can't, and I'm not interested in researching it. However once more your logic is deficient: I'd remind you of the axiom that "absence of evidence is not evidence of absence"... I'm afraid it's your responsibility to demonstrate that every Pascal (and related) compiler that had OOP facilities also had properties.

However, even if there was a full overlap of "compilers with properties" and "compilers with OOP", that does not demonstrate a causal relationship: there is no reason why a compiler that supported OOP could not omit properties from the language implemented, and I've already demonstrated that you do not need to use OOP facilities to be able to use properties which implies strongly that a compiler could be easily written to support properties at the unit level but not OOP... in fact I've done that, but the properties exposed runtime intrinsics rather than being fully programmable.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: alpine on October 09, 2021, 03:41:29 pm
@Seenkao,
Can you clarify please, what do you mean under the term "functional programming"? Lambda calculus? Or actually, you mean "procedural programming" which in turn is derivation of "imperative programming"?

(functional programming ≠ imperative programming)
Благодарю. Да, вы правы, тут я в очередной раз "в своих мыслях", и немного в другую степь ушёл. Я про процедурное программирование, путаю периодически. Хотя большей частью это всё связано.

yandex translate:
Thanks. Yes, you are right, here I am again "in my thoughts", and I went to a slightly different steppe. I'm talking about procedural programming, I get confused from time to time. Although for the most part all this is interconnected.
*snip*
In that case I will conclude that most of the discussion is provoked by misunderstanding of what is written, either by confusion of terms or by use of automatic translation. I'd say that I know Russian fairly well (not my native, tho) but still can't get your point.

You're arguing that exception handling is bad, because it is implied by OOP, which in turn is bad, because everything can be written procedural and without objects? Did I get it right?   

I'll remind also the OP's original topic title (it is written at the beginning of the each post). It is about "try..finally", which is in turn RAII. RAII is not directly connected with OOP.  In fact, many non-OOP languages have exception handling, incl. some SQL scripts.

Then the 440bx standpoint that is actually revealed quite late into the discussion - exception handling is bad, because it is the only way to return error when assigning to a property, which is part of the Pascal implementation of OOP. Because of that developer is forced to use it, and that is presumably a bad thing.

@440bx,
That is the way I'm getting it, correct me if I'm wrong.

Anyway, would you be so kind to explain more clearly (and tightly) what is your objections about the use of "try..finally" in Pascal, without derailing the whole topic?

I'm afraid you've already dеrailed it.

Edit: Corrected an ambiguity in the last sentence.
Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 03:56:54 pm
Then the 440bx standpoint that is actually revealed quite late into the discussion - exception handling is bad, because it is the only way to return error when assigning to a property, which is part of the Pascal implementation of OOP. Because of that developer is forced to use it, and that is presumably a bad thing.
I'm not sure why you say "quite late" given that I stated my view on the matter in my very first post in this thread.

@440bx,
That is the way I'm getting it, correct me if I'm wrong.
Exceptions are great when a program has to deal with unpredictable behavior such as accessing some resource that is _not_ under its control.  That's what exceptions are for.  Using exceptions to simply inform the caller that something unexpected happened is a gross misuse of exceptions.  A prime example is their use in setters to inform the caller an error or unexpected condition took place.   

Title: Re: What is good in using try..finally?
Post by: alpine on October 09, 2021, 04:14:01 pm
Then the 440bx standpoint that is actually revealed quite late into the discussion - exception handling is bad, because it is the only way to return error when assigning to a property, which is part of the Pascal implementation of OOP. Because of that developer is forced to use it, and that is presumably a bad thing.
I'm not sure why you say "quite late" given that I stated my view on the matter in my very first post in this thread.
As late as of reply #46. There is your first mentioning of "properties".

@440bx,
That is the way I'm getting it, correct me if I'm wrong.
Exceptions are great when a program has to deal with unpredictable behavior such as accessing some resource that is _not_ under its control.  That's what exceptions are for.  Using exceptions to simply inform the caller that something unexpected happened is a gross misuse of exceptions.  A prime example is their use in setters to inform the caller an error or unexpected condition took place.
Why you consider that wrong?
Title: Re: What is good in using try..finally?
Post by: kupferstecher on October 09, 2021, 05:57:09 pm
*snip*
As per statistics finally is 70X more used than except. Still to me try..except is the more natural use (just like in C++ there is only try..catch).
The prevalence of the finally is because it is a common practice to do this:
Code: Pascal  [Select][+][-]
  1.   L := TStringList.Create;
  2.   try
  3.     // use L
  4.   finally
  5.     L.Free;
  6.   end;


In my understanding try..finally doesn't really handle an exception, as it re-raises it directly after executing the finally block. An unhandled exception stops the application, which would render the above code useless. But in a GUI-application there is the LCL above handling the exception. One could see it as a nested try block, always with the LCLs try..except in the very top. And because it is there, it's not needed in the levels below. I see it as a concept, that an exception should bring the program flow immediately back to the application loop, and thats where the LCLs try..except is located. The "immediately" is only delayed by the finally-blocks in deeper code levels that clean up the mess that the exception caused.

application.inc:
Code: Pascal  [Select][+][-]
  1. {------------------------------------------------------------------------------
  2.   TApplication RunLoop
  3.   control is passed to event processor.
  4. ------------------------------------------------------------------------------}
  5. procedure TApplication.RunLoop;
  6. begin
  7.   repeat
  8.     if CaptureExceptions then
  9.       try // run with try..except
  10.         HandleMessage;
  11.       except
  12.         HandleException(Self);
  13.       end
  14.     else
  15.       HandleMessage; // run without try..except
  16.   until Terminated;
  17. end;    

Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 06:10:03 pm
As late as of reply #46. There is your first mentioning of "properties".
I mentioned the problem in my very first post.  I mentioned properties as an example of a construct that causes the problem in post #46.


Why you consider that wrong?
because cross stack frame gotos should not be used to handle run of the mill errors.  Cross stack frame gotos (exceptions) can cause a myriad of problems, they should be used when they are the only way to handle an error (for instance, access violations caused by an attempt to read memory that isn't managed by the program)
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 08:18:44 pm
because cross stack frame gotos should not be used to handle run of the mill errors.  Cross stack frame gotos (exceptions) can cause a myriad of problems, they should be used when they are the only way to handle an error (for instance, access violations caused by an attempt to read memory that isn't managed by the program)

As you pointed out in your #9... agreed, and the cross-frame issue is also one I tried to mention when I first posted in this thread (#35): it's what distinguishes exceptions from try/finally. And the problems are specifically what Warfley found himself wrestling with when he was working on coroutines a few weeks ago.

I'd cautiously agree with your position in #9 that a program never actually /needs/ try/finally, but it's useful syntactic sugar. And given the introduction of that bit of syntactic sugar, I think it's arguably unfortunate that the Object Pascal designers didn't introduce something comparable to accommodate "nearby" failures such as predictable albeit uncommon errors in property getters or setters. But I really don't like the bad argument that condemns OOP because of this one specific problem in the way that people tend to use this one specific language implementation.

MarkMLl


MarkMLl
Title: Re: What is good in using try..finally?
Post by: Martin_fr on October 09, 2021, 09:06:44 pm
As late as of reply #46. There is your first mentioning of "properties".
I mentioned the problem in my very first post.  I mentioned properties as an example of a construct that causes the problem in post #46.
Quote
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.

1) The "Pascal implementation" of non OOP, also forces the user. (e.g. StrToInt)

2) I am assuming that in the quoted text "Pascal implementation" refers to the rtl/fcl/lcl/...
Neither OOP itself, nor the way the fpc compiler handles it, introduce any such force.
Neither OOP itself, nor the way the fpc compiler handles it, demand that code that can return an error must go into a property.
Such code can (within OOP) be written in other ways, that can return the error as result (or out param, or via a LastError call). All at the choice of the author of any code (including frameworks).

Yet, if "Pascal implementation" refers to the rtl/fcl/lcl/ then yes, the rtl/fcl/lcl introduce such "possibility" (see below, not always a "force") by introducing classes that contain properties that raise exceptions. But also introducing functions (non-oop)

Sure StrToInt is easier to replace than e.g. TList. But then
- StrToInt is just one example
- Without oop, instead of TList you use arrays (or similar constructs). For those you need to check bounds in advance. For TList you can check bounds in advance too, avoiding the need of "try except" blocks, as you ensure no exception will be risen. So in this case the rtl/fcl/lcl still do NOT (always or "often") force the user to use "try except"

Some classes may not offer advanced checks to avoid exceptions. But then, neither does StrToInt.
The user can then chose not to use those classes at all (same as StrToInt).

I think the example (quoted above) is poorly worded:
1) "Pascal implementation of OOP" should make it clear that it is about the frameworks. And then once that is clear, it is the entire framework, including non-oop parts.
2) "often forces" well actually no: not forces, merely offers. In many cases alternative options are given. But sometimes, maybe yes: Some parts of the framework forces the use of exceptions, IF the user wants to use that part of the framework. (but again OOP and non-OOP).
Title: Re: What is good in using try..finally?
Post by: alpine on October 09, 2021, 09:12:39 pm
As late as of reply #46. There is your first mentioning of "properties".
I mentioned the problem in my very first post.  I mentioned properties as an example of a construct that causes the problem in post #46.

Turning back to your first post (reply #9):
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. 
Here I can see recommendations, not problems.

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

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.
Here all readers should guess that you're actually talking about properties.

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.
It is actually more that a goto, it is a language construct with it's defined semantics. Otherwise, we can say for every control structure: it is nothing more than a goto. What about the threads? Aren't they worst than "try-except"?

Why you consider that wrong?
because cross stack frame gotos should not be used to handle run of the mill errors.  Cross stack frame gotos (exceptions) can cause a myriad of problems, they should be used when they are the only way to handle an error (for instance, access violations caused by an attempt to read memory that isn't managed by the program)
Isn't it error to try accessing e.g. TStrings.Items[ I ] with I beyond the current size of the collection?

What kind (myraid) of problems can cause the use of "try-except"? Please specify.

*snip*
As you pointed out in your #9... agreed, and the cross-frame issue is also one I tried to mention when I first posted in this thread (#35): it's what distinguishes exceptions from try/finally. And the problems are specifically what Warfley found himself wrestling with when he was working on coroutines a few weeks ago.
I agree that the implementation of such features could be treacherous. But we're discussing their usage, not implementation.
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 09, 2021, 09:24:14 pm
Neither OOP itself, nor the way the fpc compiler handles it, introduce any such force.
Neither OOP itself, nor the way the fpc compiler handles it, demand that code that can return an error must go into a property.
Such code can (within OOP) be written in other ways, that can return the error as result (or out param, or via a LastError call). All at the choice of the author of any code (including frameworks).

Yet, if "Pascal implementation" refers to the rtl/fcl/lcl/ then yes, the rtl/fcl/lcl introduce such "possibility" (see below, not always a "force") by introducing classes that contain properties that raise exceptions. But also introducing functions (non-oop)

I rarely use emoticons. I never use animated emoticons, and look down on people who do.

But it's getting to the point where it's unfortunate that this particular instance of SMF hasn't enabled :horse: :-)

Somewhat later. As a couple of historical points:

* By the late 1960s, the Burroughs ALGOL compiler allowed a procedure to be associated with an exceptional condition such as a divide by zero, but this was more like an interrupt handler than part of the normal block structure.

* The Wp article https://en.wikipedia.org/wiki/Mesa_(programming_language)#Syntax refers to Xerox PARC hiring an unidentified graduate from Colorado who defined their exception handling semantics, but elsewhere Jim Mitchell (https://en.wikipedia.org/wiki/James_G._Mitchell) is credited with doing the work there.

MarkMLl

Title: Re: What is good in using try..finally?
Post by: 440bx on October 09, 2021, 11:11:38 pm
But I really don't like the bad argument that condemns OOP because of this one specific problem in the way that people tend to use this one specific language implementation.
I don't condemn OOP just because of that.  That's just one (1) of the many reasons I strongly dislike OOP.  The reason I'm elaborating on exceptions is because it's closely related to the initial topic of the thread.




1) The "Pascal implementation" of non OOP, also forces the user. (e.g. StrToInt)
Yes, that is true but, it would be very easy to provide an implementation of StrToInt that didn't raise an exception in case of a conversion error.  The same cannot be said about setters.

2) I am assuming that in the quoted text "Pascal implementation" refers to the rtl/fcl/lcl/...
Actually, it refers to how the OOP portion is designed and implemented.  That would include the RTL but, the implementation of the LCL (for instance) is, to a significant extent, a result of how OOP is implemented in Pascal.

Neither OOP itself, nor the way the fpc compiler handles it, introduce any such force.
That statement is valid only if properties are not considered part of OOP, which is something some participants in this thread claim.  A claim that I consider "unconvincing".

Neither OOP itself, nor the way the fpc compiler handles it, demand that code that can return an error must go into a property.
Maybe so but, when a programmer uses properties and encounters an error condition in a setter, there doesn't seem to be any alternatives to raising an exception.

Such code can (within OOP) be written in other ways, that can return the error as result (or out param, or via a LastError call). All at the choice of the author of any code (including frameworks).
I can see that but, then it wouldn't be a property anymore.  What I'm saying here is, the language provides properties, programmers use them because they are available and, as a result they have to use exceptions.  IOW, I don't see Pascal programmers making any efforts to avoid setters and the consequent need for exceptions.


- Without oop, instead of TList you use arrays (or similar constructs). For those you need to check bounds in advance. For TList you can check bounds in advance too, avoiding the need of "try except" blocks, as you ensure no exception will be risen. So in this case the rtl/fcl/lcl still do NOT (always or "often") force the user to use "try except"
From the point of view of what can be done, what you've presented is very reasonable but,  from what I've seen, OOP programmers would rather enclose their code in a "try-except" than do any pre-condition checking.

Some classes may not offer advanced checks to avoid exceptions. But then, neither does StrToInt.
The user can then chose not to use those classes at all (same as StrToInt).
It seems to me that the better solution would be to have implementations don't depend on exceptions to return errors.

2) "often forces" well actually no: not forces, merely offers. In many cases alternative options are given. But sometimes, maybe yes: Some parts of the framework forces the use of exceptions, IF the user wants to use that part of the framework. (but again OOP and non-OOP).
What good is it to have a framework if some of it has to be avoided ?



Here all readers should guess that you're actually talking about properties.
I'm definitely guilty of expecting the readers to know Object Pascal and be aware of properties among other things.  I guess my expectations are misplaced.

Isn't it error to try accessing e.g. TStrings.Items[ I ] with I beyond the current size of the collection?
I've never used TStrings, I'm going to guess that it is an error.  Are you using that as an example to justify the use of exceptions ?

What kind (myraid) of problems can cause the use of "try-except"? Please specify.
Yes, there are really a myriad but, one of them is already enough to use them only when strictly necessary and that is, it is a cross stack frame goto.  A goto that does not cross stack frames is already undesirable, one that crosses stack frames is orders of magnitud more undesirable and, you should know why. 
Title: Re: What is good in using try..finally?
Post by: Martin_fr on October 10, 2021, 12:14:49 am
You imply (falsely) that properties must be used for everything.
There are existing properties, that do not (never) throw exceptions. Those are examples where properties cause no problem (in relation to a discussion on exceptions).

Code that need exceptions, well it can be implemented as a method, a "function of object" that can return the error. The option of having properties is not a mandate to use nothing else but properties.

The existence of code throwing exceptions (including in properties) is not mandated by OOP, nor by the compiler, nor by the existence of properties. It is a choice.
Only due to the use in the framework, the choice becomes limited. (for both OOP and non-OOP)

Your argument reads (to me) like the quite ridiculous following statement: If you do not use OOP, and the language provides a "Procedure" that does not return a result, then you must always use such a procedure instead of function, if you want to trigger an action (including changing some value). Thus if an action can not be executed, the only way to return the error is an exception.

Quote
What good is it to have a framework if some of it has to be avoided ?
What good is it, that there is a StrToInt, if you have to avoid it?

Mind, it does not matter if it is easy to avoid or not. The point is that if it is to be avoided, then why is it there at all.


Anyway, you get the last word. As I do not have to offer anything on the original thread. So if you wish tear my statement apart.
Title: Re: What is good in using try..finally?
Post by: alpine on October 10, 2021, 12:22:22 am
*snip*
Here all readers should guess that you're actually talking about properties.
I'm definitely guilty of expecting the readers to know Object Pascal and be aware of properties among other things.  I guess my expectations are misplaced.

Isn't it error to try accessing e.g. TStrings.Items[ I ] with I beyond the current size of the collection?
I've never used TStrings, I'm going to guess that it is an error.  Are you using that as an example to justify the use of exceptions ?
Yes.
I'm definitely guilty of expecting the skeptics of OOP/exceptions to know Object Pascal and be aware of collections among other things.  I guess my expectations are misplaced.

What kind (myraid) of problems can cause the use of "try-except"? Please specify.
Yes, there are really a myriad but, one of them is already enough to use them only when strictly necessary and that is, it is a cross stack frame goto.  A goto that does not cross stack frames is already undesirable, one that crosses stack frames is orders of magnitud more undesirable and, you should know why.
Should I know why? No, I shouldn't. I am a novice, please explain, why?
Title: Re: What is good in using try..finally?
Post by: 440bx on October 10, 2021, 12:47:43 am
You imply (falsely) that properties must be used for everything.
I don't believe I ever implied that.

Code that need exceptions, well it can be implemented as a method, a "function of object" that can return the error. The option of having properties is not a mandate to use nothing else but properties.
if the code isn't dealing with resources it does not manage then it shouldn't need exceptions. 

The existence of code throwing exceptions (including in properties) is not mandated by OOP, nor by the compiler, nor by the existence of properties. It is a choice.
looks like it's a "choice" a bit more common than it should be.

Only due to the use in the framework, the choice becomes limited. (for both OOP and non-OOP)
isn't limiting choices a way of forcing the remaining choices ?

Quote
What good is it to have a framework if some of it has to be avoided ?
What good is it, that there is a StrToInt, if you have to avoid it?
good question.

Mind, it does not matter if it is easy to avoid or not. The point is that if it is to be avoided, then why is it there at all.
because the functionality is useful, unfortunately, it reports errors using an exception mechanism.


Anyway, you get the last word. As I do not have to offer anything on the original thread. So if you wish tear my statement apart.
I'll make an exception and let you have the last word.  This is an Object Oriented Post (OOP)



I'm definitely guilty of expecting the skeptics of OOP/exceptions to know Object Pascal and be aware of collections among other things.  I guess my expectations are misplaced.
Considering that collections such as TString are not part of the language definition, knowing or not knowing about them is not a reflection on an individual's knowledge of Object Pascal. 

Should I know why? No, I shouldn't. I am a novice, please explain, why?
In that case, I recommend you read the book "Oh Pascal" by Doug Cooper.  Excellent book, it will answer that question for you and many more. Good reading for a novice.
Title: Re: What is good in using try..finally?
Post by: Warfley on October 10, 2021, 01:03:51 am
I tried to avoid this whole properties-oop-exceptions discussion as I think it is completely pointless, but here is just briefly something about that.

1. Properties are not part of OOP. This is easiely proovable. If it was part of OOP, then all language that implement the whole featureset of OOP would implement this. Java is the posterboy OOP language and doesn't implement properties therefore properties are not part of OOP.
Btw. neither does the UML, which is THE formal language to specify OOP architectures.

2. Properties do not require exceptions. Properties are just syntactic sugar around functions of the form "procedure Setter(AValue: AType)" and "function Getter: AType" and thereby share the same restrictions as these. Yes a function of the form "procedure Setter(AValue: AType)" can not have a return value, so if this function would need one, you wouldn't write the function like this. Same with properties. Also it should be noted that if exceptions didn't exist it does not imply that all functions that could raise an exception need a return value. A member variable within the class could be used to indicate an error (like errno does on Linux), and rather than raising an exception inside a setter, you just set that variable and call exit.

Properties can use exceptions, that doesn't mean that they require exceptions. Not having exceptions would be a little bit more inconvinient, but you could either: 1. in this cases not use properties but custom signature setters with a return value or 2. use a variable to write in the error and check this.

Just because many people currently use exceptions here does not mean that they are required. It's like saying: "today all newly build houses are made of concrete, therefore concrete is required to build houses". The reason people use exceptions is just because they are available and make this easier than the alternatives.

3. If you want to make the argument that the OOP implementation of modern object pascal requires exceptions, then you don't need to argue about properties. Just look at classes.
Through the design of classes in modern Object Pascal, the memory management is done implicitly by the constructor and destructor. Calling the constructor will automatically return the pointer to the newly allocated memory.
This means the the constructor can not have a return value, as the return value is the self address and is added implicetly by the compiler. You have also no ability to stop the creation of the object if you encounter an error within the constructor, except if you use exceptions. So if your constructor runs into an error you need to use excpetions.
The difference to your property example is, that it is very easy to not use properties if you need a return value, simply use manual getter and setter functions. But if you use classes, you *must* use the constructor and if this can run into an error you *must* use exceptions.

That said, even this is not inherent to OOP in any shape or form. This is just how it was chosen to implement Classes in Object Pascal. This could easiely be changed by having the ability to set the return value of the constructor manually rather than automatically.
Other languages like C++, which allow for their classes to be stack allocated, don't run into that problem.

As you pointed out in your #9... agreed, and the cross-frame issue is also one I tried to mention when I first posted in this thread (#35): it's what distinguishes exceptions from try/finally. And the problems are specifically what Warfley found himself wrestling with when he was working on coroutines a few weeks ago.

I want to say that I still consider this a bug in the RTL. SetJmp/LongJmp not handling the exception state transparently means that they simply can not be used with exceptions. In C++, which also supports SetJmp/LongJmp as well as exceptions this isn't a case and these functions handle the exception state for you.

I know that there are reasons why these functions don't handle the exception state in the FPC (as they are used to implement exceptions) but I still think either these functions should support the exception state, or are not publically availabe and usable when exceptions are enabled (as there is currently no way to use them without breaking the program state), or to the very least, have the documentation state that they are basically unusable if exceptions are enabled.
As it stands these functions are currently just a landmine that will blow up on you if you try to use them.

In my understanding try..finally doesn't really handle an exception, as it re-raises it directly after executing the finally block.

Lastly I want to repeat what I've wrote a little bit earlier. Try-finally should not only be associated with exceptions. I think is a little bit because the naming (i.e. having the "try" part), but try-finally is much more than that. In fact even without exceptions try-finally would be massively useful.

A finally block is not only triggered on an exceptions but on other jumps as well, namely Exit, Break and Continue.
Code: Pascal  [Select][+][-]
  1.   while True do
  2.   begin
  3.     try
  4.       break;
  5.     finally
  6.       WriteLn('Finally');
  7.     end;
  8.   end;
This makes it massively useful. E.g. if you have a loop which creates an object in it's loop body and you exit via break or skip via continue, you can use finally to make sure that the object will be freed.
Code: Pascal  [Select][+][-]
  1. for FileName in FileNames do
  2. begin
  3.   fs := TFileStream.Create(FileName, fmOpenRead);
  4.   try
  5.     w := fs.ReadWord;
  6.     if w = 0 then
  7.       Break;
  8.     if w > 1024 then
  9.       Continue;
  10.     // long algorithm
  11.   finally
  12.     fs.Free;
  13.   end;
  14. end;

So I think assocating try-finally only with exceptions does a hughe disservice to this construct. Even in a world with no exceptions try-finally is very usefull and it is by far the feature I miss most when having to use C.
Basically it guarantees that a certain code will be executed no matter how you exit.
Title: Re: What is good in using try..finally?
Post by: Seenkao on October 10, 2021, 03:17:35 am
You're arguing that exception handling is bad, because it is implied by OOP, which in turn is bad, because everything can be written procedural and without objects? Did I get it right?
Нет! Нет! И ещё раз нет! )))
Не мешайте пожалуйста всё и сразу в одну кучу! (возможно я виноват своим двусмысленным высказыванием). В посте #55 я указал почему я это не использую. На что мне ответили, что я что-то делаю неправильно. Возможно MarkMLl мог оказаться правым на мой счёт, если бы на месте меня был кто-то другой. Но на моём месте - я. ))) И попробовав сделать всё то же самое что делаю я, он бы так же столкнулся с теми же проблемами. Код, с которым я работаю достаточно нативен. Я не использую LCL и многие классы (да, я не люблю ООП, но я видел немало программ которые хорошо сделаны с помощью ООП и они не сильно "раздутые" - небольшого размера). И перечитывая тему, я начал понимать, почему в моём коде не срабатывают подобное.

Для того чтоб использовать try..exception/try..finally надо включать в них вызываемый код (что обычно и происходит в ООП). А в моём коде, я проверяю не включаемый код, а конечный результат. И, я не могу использовать данные методы для проверки, потому что они не будут "пытаться" сделать. Уже всё сделано и обрабатывать уже нечего. Ошибка уже совершена (в чём-то тут моя вина, и я этого не понимал изначально).

Потому, надо смотреть, что происходит. Если вызывается процедура/функция, то её можно обработать подобным образом. Она попытается сработать, вызовет исключение и  вернётся (сделав вид, что код не сработал). И тогда ошибку обойдём. Если мы обрабатываем конечный результат, мы не сможем ни чего обработать данными методами.

Yandex translate:
No! No! And once again, no! )))
Please do not interfere all at once in one pile! (perhaps I am to blame for my ambiguous statement). In post #55 I indicated why I don't use it. To which I was told that I was doing something wrong. Perhaps MarkMLl could have been right about me if someone else had been in my place. But I am in my place.))) And if he tried to do all the same things that I do, he would also face the same problems. The code I'm working with is quite native. I don't use LCL and many classes (yes, I don't like OOP, but I've seen a lot of programs that are well made with OOP and they are not very "bloated" - small in size). And rereading the topic, I began to understand why such things do not work in my code.

In order to use try..exception/try..finally it is necessary to include the called code in them (which usually happens in OOP). And in my code, I'm not checking the included code, but the final result. And, I can't use these methods for verification because they won't "try" to do. Everything is already done and there is nothing left to process. The mistake has already been made (something is my fault here, and I didn't understand it initially).

Therefore, we need to look at what is happening. If a procedure/function is called, then it can be handled in a similar way. It will try to work, raise an exception and return (pretending that the code did not work). And then we will bypass the error. If we process the final result, we will not be able to process anything with these methods.

Quote from: y.ivanov
Then the 440bx standpoint that is actually revealed quite late into the discussion - exception handling is bad, because it is the only way to return error when assigning to a property, which is part of the Pascal implementation of OOP. Because of that developer is forced to use it, and that is presumably a bad thing.
По сути, я уже ответил на это. Это не зависит от того, какое программирование мы используем. Процедурное или ООП. Это зависит от того, что мы делаем в коде. Конечный результат так обрабатывать (как я понимаю) просто нельзя. Это создано для попытки вызова процедуры/функции или какого-то кода - что может вызвать исключение. Результат - не может вызвать исключения (код уже выполнен и мы либо уже получили исключение или код просто отработал). )))

Минус подобного подхода в том, что код может выполняться несколько раз, и ни разу не выполнится. А в "сокрытых" (вызываемых) процедурах/функциях может лежать очень немало кода... что может отнять достаточное время на обработку исключения.

Yandex translate:
In fact, I have already answered this. It doesn't depend on what kind of programming we use. Procedural or OOP. It depends on what we are doing in the code. The end result can't be processed like that (as I understand it). This is created to attempt to call a procedure/function or some code - which may cause an exception. The result is that it cannot cause exceptions (the code has already been executed and we either have already received an exception or the code just worked). )))

The disadvantage of this approach is that the code can be executed several times, and it will never be executed. And there can be a lot of code in "hidden" (called) procedures/functions... which may take up enough time to process the exception.

----------------------------------------------------------------
Благодарю всех за обсуждение подобных тем! Это вправляет иногда мозги на место. И зачастую приносит немало информации!
... жаль, что такие обсуждения со временем теряются...
Eng:
Thank you all for discussing such topics! This sometimes puts the brains in place. And often brings a lot of information!
... it's a pity that such discussions are lost over time...
Title: Re: What is good in using try..finally?
Post by: dbannon on October 10, 2021, 06:17:52 am
OK, so I have been benchmarking TSet against AVLTree. I have a just over 2000 files in a directory, I read each one into a string and save a pointer to record containing the file content and its filename into both the AVLTree and a TSet. Repeat a 1000 times and and then do another 1000 where we stop just short of poking the pointer into the structure.

My initial "read the file" function just sets the length of a string to the file size and I point a filestream at it.  No try..finally and no exception handling.

So, having a good feel about how my benchmark code works, what if I add a try..finally and a exception handler ?

Stripped down I get

 for each run of 2k files, I add a Try..finally and it jumps to 17.7mS, and exception handler gives me 17.9mS. Repeated enough times to feel the numbers are significant.

So, yes, adding try..finally and an exception handler does slow down your code. Lets compare that to putting a FileExists() call in the loop ?  21.5mS.  And FileExists() is no guarantee that the file will open or, even that it does in fact exist. Checking i/o results uses up cycles too.

Lots of network file sharing tools lie. NFS used to be very prone to dropping a connection but the client still has the metadata. I had an end user recently using a buggy file encryption system on his windows box, try opening a file "sometimes" and it would fail, try again a mS later and all good. We could all go on ....

So, just concentration on file i/o, yes, test if the file is there (fingers crossed) or or just try opening it and, on that rare occasion where it does not work, rely on try..finally and exceptions. My numbers indicate which is a faster !

Hope you don't mind me butting in !

Davo 
Title: Re: What is good in using try..finally?
Post by: PierceNg on October 10, 2021, 06:31:20 am
So, just concentration on file i/o, yes, test if the file is there (fingers crossed) or or just try opening it and, on that rare occasion where it does not work, rely on try..finally and exceptions. My numbers indicate which is a faster !

Hope you don't mind me butting in !

Davo

Try
  experiment
Finally
  reportOutcome 

Good stuff!
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 09:23:54 am
Neither OOP itself, nor the way the fpc compiler handles it, introduce any such force.
That statement is valid only if properties are not considered part of OOP, which is something some participants in this thread claim.  A claim that I consider "unconvincing".

A unit can have properties, therefore the set of (languages with properties) can- potentially at least- be larger than the set of (languages with OOP).

Apart from that I reiterate my position: the fact that Object Pascal is used in a way that encourages the use of exceptions could arguably be interpreted as a flaw in the language design, but a flaw in one language's design cannot be interpreted as a flaw in the overall OOP concept.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 09:39:21 am
I want to say that I still consider this a bug in the RTL. SetJmp/LongJmp not handling the exception state transparently means that they simply can not be used with exceptions. In C++, which also supports SetJmp/LongJmp as well as exceptions this isn't a case and these functions handle the exception state for you.

I'm trying to think back. When I was doing really low-level microkernel stuff on protected-mode x86 I postprocessed the binaries to associate far calls with call gates and coroutine operations with task transfers: my recollection is that I had absolutely no need for far jumps.

It might even be defensible to argue that with exceptions for gross error recovery and a decent coroutine implementation SetJmp/LongJmp could be removed from the language.

Quote
Lastly I want to repeat what I've wrote a little bit earlier. Try-finally should not only be associated with exceptions. I think is a little bit because the naming (i.e. having the "try" part), but try-finally is much more than that. In fact even without exceptions try-finally would be massively useful.

Which is why when discussing such things outside the context of specific syntax I usually refer to start/finally.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 09:42:49 am
In order to use try..exception/try..finally it is necessary to include the called code in them (which usually happens in OOP). And in my code, I'm not checking the included code, but the final result. And, I can't use these methods for verification because they won't "try" to do. Everything is already done and there is nothing left to process. The mistake has already been made (something is my fault here, and I didn't understand it initially).

Therefore, we need to look at what is happening. If a procedure/function is called, then it can be handled in a similar way. It will try to work, raise an exception and return (pretending that the code did not work). And then we will bypass the error. If we process the final result, we will not be able to process anything with these methods.

That doesn't quite make sense. If you have problems in that area, I suggest it would be worth starting a separate thread and posting an example.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: alpine on October 10, 2021, 11:05:04 am
Should I know why? No, I shouldn't. I am a novice, please explain, why?
In that case, I recommend you read the book "Oh Pascal" by Doug Cooper.  Excellent book, it will answer that question for you and many more. Good reading for a novice.
Thank you for the recommendation. This is a good book, indeed.

Now, I want to quote Mr.Cooper from that book, the excerpt is from "Appendix: Everything You Wanted To Know About Pascal", p.553 in my copy:
Quote
There are also extraordinary circumstances in which using gotos is permissible. Most common is the ‘I want to get out of here in a hurry’ case. Suppose, for example, that program input is coming from punched cards or tape, and an input checking procedure spots incorrect data. Since we know that there’s no point in continuing to process input, we can issue an error message and go to the very end of the program (because it’s o.k. to label an end).

  (code example)

The goto is also properly used for beating a hasty retreat from a function whose arguments are determined to be inappropriate. In these cases the desirability of graceful degradation outweighs the stigma attached to using gotos.
It doesn't prove your point, just on the contrary! It justifies goto in the case of error.

I'm definitely guilty of expecting the skeptics of OOP/exceptions to know Object Pascal and be aware of collections among other things.  I guess my expectations are misplaced.
Considering that collections such as TString are not part of the language definition, knowing or not knowing about them is not a reflection on an individual's knowledge of Object Pascal. 
You continue insisting that OOP implementation in Object Pascal forces using of "try-except" based only on the language specification? How you can do that without knowing a bit of RTL/FCL/LCL (and hence confusing OOP with the framework)? It is like to say that the sole existence of parameter-less functions in Pascal (as somebody already noted this earlier) is forcing you to do the same.


   
Title: Re: What is good in using try..finally?
Post by: 440bx on October 10, 2021, 11:54:06 am
It doesn't prove your point, just on the contrary! It justifies goto in the case of error.
It does not in any way do that.  The reason he included that _exception_ about the use of goto is because there is no "exit" and other control flow facilities in the Pascal definition he is using and, you know that.

You continue insisting that OOP implementation in Object Pascal forces using of "try-except" based only on the language specification? How you can do that without knowing a bit of RTL/FCL/LCL (and hence confusing OOP with the framework)? It is like to say that the sole existence of parameter-less functions in Pascal (as somebody already noted this earlier) is forcing you to do the same.
IOW, no one can tell that an elephant is big and heavy unless they are a veterinarian.  It's a fact that when using the Pascal implementation of OOP, particularly the Delphi and FPC implementations, the programmer will be forced to use "try-except" in many cases where they should not be necessary. 
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 12:19:00 pm
It does not in any way do that.  The reason he included that _exception_ about the use of goto is because there is no "exit" and other control flow facilities in the Pascal definition he is using and, you know that.

Having said which (and by now I'm not sure whether I'm pouring oil onto troubled water or onto the fire) I've been at a conference where exit/break and so on were criticised as being "closet gotos" so as such were to be derided. I can't remember whether the proponent of that idea had ever done any real work...

I will, again, repeat Dijkstra's position:

Quote
Please don't fall into the trap of believing that I am terribly dogmatical about [the goto statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!

I think that my position has to be that while it is always satisfying to be able to simplify an idiom, which would suggest that from the user's POV start/finally and try/except should be collapsed into a single language structure, in practical terms it's probably desirable for idioms which have vastly different runtime behaviour to be kept distinct because that (as an hypothetical example) would enable the FPC maintainers to fix the problems highlighted by Warfley by modifying the cross-frame try/except behaviour without impacting on the intra-frame start/finally.

And that allows me to propose a succinct response to OP's question: if what you're doing is strictly intra-frame (i.e. doesn't leave the current procedure/function) then you don't use try/except, since that introduces a great deal of unneeded runtime complexity and overhead.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Thaddy on October 10, 2021, 12:24:15 pm
Well, let's introduce:
Code: Pascal  [Select][+][-]
  1. try
  2.    //
  3. Fatally
  4.  
  5. // end part can not be reached....

Bit of a sick conversation, all this. One of the "finest".....
try/finally is mis-used, but simply resource protection. NOTHING else. And GOOD.
try/except is even more mis-used but satisfies its design. And even more misunderstood: exception should be used for unpredicatble code paths by programmers -, not the predectable ones: those should be trapped in your code. Predicatble exceptions? Go back to school.
Title: Re: What is good in using try..finally?
Post by: alpine on October 10, 2021, 12:40:58 pm
There were a hints that conversation was leading nowhere...
At least I've learned a Welsh word that sounds amazingly like a word from my language with the same meaning.
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 12:56:29 pm
There were a hints that conversation was leading nowhere...
At least I've learned a Welsh word that sounds amazingly like a word from my language with the same meaning.

In some renditions it stands for Traditional Welsh Protestant :-)

In any event, I think this discussion has departed a long way from answering OP's question.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: jollytall on October 10, 2021, 07:56:18 pm
In any event, I think this discussion has departed a long way from answering OP's question.

Yes, but I really enjoyed reading it. Also I learnt a lot, as I also summarized above.

Two quick reactions:

That said, even this is not inherent to OOP in any shape or form. This is just how it was chosen to implement Classes in Object Pascal. This could easiely be changed by having the ability to set the return value of the constructor manually rather than automatically.
Other languages like C++, which allow for their classes to be stack allocated, don't run into that problem.
Although not said explicitly, it sounds as FPC classes were pascal OOP and comparable to C++ classes, and this comparison leads to points like stack vs. heap. Important to mention that classes is not core OOP (at least in my eyes) even in pascal. You can always use object instead of class and that behaves much more similar to C++ class, can be in stack, etc.
Obviously, if you want to use Lazarus components, those are classes, but you do not have to use them and you can still use OOP. This leads to my second point.

Writing code without try..except, try..finally or even without lcl, without classes, etc. is absolutely possible. I can also agree that with sufficient knowledge and effort the resulting asm can be as good or even better, smaller, faster than these more complex structures.
I remember I wrote a program in pure Z80 assembler some 40 years ago. That was small (had to be, as the total RAM was 48Kb) and efficient but took me weeks to write. Today I could write the same in an hour using modern tools.
Also I remember even in Delphi first I made Windows GUI applications calling Windows API calls directly. Again it worked, but then Forms, and other components made it much simpler, faster.
I feel the same discussion around try now. I see it as a huge productivity gain if used smartly. If we spend only half of the time saved on testing the result, probably we will have a better code than doing everything ourselves without it.
Title: Re: What is good in using try..finally?
Post by: MarkMLl on October 10, 2021, 09:49:27 pm
In any event, I think this discussion has departed a long way from answering OP's question.

Yes, but I really enjoyed reading it. Also I learnt a lot, as I also summarized above.

Thanks for the feedback on that, IMO it's really quite important particularly when the community starts wibbling.

Thinking about your point about being able to avoid start/finally and try/except:

In the first case, I think it's good style to be able to write something like

Code: Pascal  [Select][+][-]
  1.   Open(something);
  2.   try
  3. ... do stuff here
  4.   finally
  5.     Close(something)
  6.   end;
  7.  

Now in practical terms the "do stuff here" might be trivial and not likely to cause problems, but that layout still draws ones eye to the fact that the file (or whatever) is being explicitly closed.

In the second case: I've got a lot of code based on a compiler-compiler originally published in '64. My first implementation of that was in about '86, and the only way to implement the abend specified by the algorithm (which proceeded to produce error messages showing what had gone wrong where) was by using a setjmp/longjmp (this was back in the days of MT+86 and the earliest versions of Turbo Pascal). But that code translated surprisingly easily to use an exception when the facility became available (i.e. using conditional defines), which had the advantage that problems could be directed to a code fragment which hadn't yet been touched by execution: the error handling became purely defined by the syntax of the program, rather than by the runtime control flow.

So as I've said already: exceptions shouldn't be overused, and that's particularly the case when they are likely to go via the OS. But they have their uses.

MarkMLl
Title: Re: What is good in using try..finally?
Post by: Warfley on October 11, 2021, 01:03:12 am
It might even be defensible to argue that with exceptions for gross error recovery and a decent coroutine implementation SetJmp/LongJmp could be removed from the language.
I would agree but personally I like these really academic and experimental projects which sometimes require you getting "dirty" and often require such low level functions. So while in productive code i don't think that such jumps are required, I wouldnt like taking them away
TinyPortal © 2005-2018