You asked, he answered!
Find below the questions and answers from Bruce Armstrong's (originally done by Oscar Tobar) presentation on Best practices for managing exceptions and errors in PowerBuilder.
Q: Are there any performance benefits to using this?
No. It does streamline the error handling and often allows you to handle recover from every handling earier. But it does nothing to improve performance.
Q: Aren't you still going to end up with just as much code, just in a somewhat different order? (In fact, more code, because you have all those extra objects, e.g. your custom exceptions.)
Not necessarily. Because you can move clean up logic (disconnect from database, destroy locally created objects) in the finally block, you can consolidate cleanup that might have to be repeated seperately without exceptions. However, the point of using an exception handling approach isn’t to reduce lines of code. The point is to streamline error handling. Note that you also don’t have to create the custom classes unless you want to trap for different specific exceptions from your code. You could simply create a local variable of type throwable or runtimeerror and throw that.
Q: Stupid question: How does putting code in Finally differ from putting that same code immediately after End Try?
Not stupid at all. First, code that comes after the finally block wouldn’t be executed if the routine raised an exception of its one. Secondly, you don’t normally have code after a finally section. The finally section in most cases would be the last part of the script.
Q: Actually, RuntimeError has a lot more Properties than Throwable, so wouldn't it be better to inherit from it?
Yes it would. For some reason I thought we ran into problems doing when we first started using it (on much earlier versions of PowerBuilder). Seems to work fine with 12.5. Runtimeerror does give you some additonal attributes (object, class, method, line of code). However, as I relate a bit further below, we simply added that information to the end of the error message. If you take that approach, I’m not sure basing the class on runtimeerror offers any advantage. The one case where it does make sense, brought up by another commenter below, is for those events (e.g., contructor, destructor) where PowerBuilder does not allow you to declare the exception type thrown by the script and requires that it be of type runtimeerror.
Q: I think that C# allows to use Finally Blocks.
Absolutely it does. What I said in the webcast is the C# does allow the use of a return code within a finally clause (see http://social.msdn.microsoft.com/Forums/en/netfxbcl/thread/87faf259-3c54-4f3a-8d2b-ff82de44992f). Java does, but it’s frowned on ( see http://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java) What I said in the webcast is that if you used a return in a finally block in PowerScript (which allows it) it would throw an error if you compiled to code in a .Net target because C# wouldn’t allow the return code in its finally block.
Q: can try/catch be nested inside other try/catch? Yes.
Q: How can I control some VM errors from code ?
You would have to see if you could trap them from the systemerror event on the application object. If they aren’t catchable there, they probably can’t be caught within PowerBuilder.
Q: how can you output the full stack trace?
Q: What version of powerbuilder did the inner exception get added? I cannot see it in 11.5
This was a mistatement on my part. In the application I work on, we put together stack trace type information (object, script, line of code, etc) and append it to the error message. If the exception is caught by a calling function and then rethrown, we do the same thing for the new exception, and then append on the message from the original exception. That gives us the full stack trace info.
Q: How do you handle Exceptions when the calling function is POSTed?
You can’t trap an exception from posted code in the calling script, as the calling script will have completed before the posted code runs. You would have to trap that error in the SystemError event of the application object.
Q: For implementing into an existing large legacy application, we are looking for some advice? As every object that throws must be caught, it's sometimes difficult to add exception throwing at a base level as it affects all descendants. Also, would you recommend descending all system/code exceptions from Error and all business exceptions (such as a ValidationException) from Exception?
I don’t have any specific recommendations for the first part of this. It’s like the question of how you reverse engineer PFC into an application that wasn’t originally based on it. It’s a lot of work and you have to take it in as small of pieces as you can. I’m afraid there’s no shortcut. You don’t want to use Error, as it’s the old error handling mechanism in PoweBuilder that requres a RaiseError rather than a throw. It’s a completely different error handling method. You might consider runtimeerror as the basis for system/code exceptions because it includes the same information you’re probably looking for in the error object (object, class, script, line of code, etc). However, as I mentioned earlier, we simply add that information to the error message. If that is the case, then you could simply base all your classes off of throwable.
Q: How do you throw a custom exception descending directly from Throwable from a system event (such as constructor or destructor) that only alllows RunTimeError?
You would have to declare the custom exception to inherit from runtimeerror.
Q: How to handle graphical datawindow exceptions or errors?
The datawindow has a number of error events (dberror, error and wserror) that occur when a datawindow error occur. You would add code to those events to trap those errors.
Q: I have a side question about dw retrieve. I have a stored procedure based datawindow, but at runtime sometimes the retrieve is not the complete result set. For those with over 1000 rows for example, why does it sometimes retrieve partial?
What I have seen with Oracle, and with non stored procedure based datawindows as well, is that if the column sizes in the result set are larger than those defined in the datawindow, you will encounter problems when the first row that returns data larger than the column is returned. With some versions of PowerBuilder, the datawindow would simply truncated the data to the datawindow column width and not indicate there was a problem. Other versions of PowerBuilder would halt the retrieval of the data at the row before the one with the oversized data (and once again not indicate there was a problem). Not sure that’s specifically what you’re seeing, but it does seem to be a similar scenerio.
Q: If I code try catch in application open event, can it catch exceptions from the whole application.
My application opens an MDI frame with a menu and each menu opens sheets and so on. No, the open event will terminate as soon as the application is started, and the exception handling you declared there will no longer be in effect. The only place you can do application global error handling is in the systemerror event of the application object.
Q: If I have a sp with a throwable error in Sqlanywhere can I retrieve the error msg in pb code ?
I’m actually not that familiar with SQL Anywhere exception handling. I know with Oracle any ununhandled user defined exception gets returned to the application as a SQL error with a db code between -20000 and -29999. I imagine that errors throws from SQL Anywhere and not handled within the SQL Anywhere code would have a similar outcome. Q: If you are logging in the exception handling, how do you handle errors in writing the log? I’d probably throw an error mesage to the user at that point. Q: Can exceptions be thrown back from a daughter process? If it’s a subroutine called from a parent routine, then yes. If it’s code running on a seperate thread you’d have to include some method of the daughter process to return status information back to the parent routine, including any errors that are encountered. It wouldn’t be an exception though.
Q: Is it better to have a custom exception objet for each error case or a few one for all cases ?
That’s your judgment call. Custom exceptions are really only needed if you want to have try blocks that have different catch blocks for different types of errors. If you don’t need that sophisticated of handling of the errors, then you could even just use the throwable or runtimeerror classes directly without creating any custom descendants.
Q: is there a version of the PFC that embeds the new objects he's discussing?
No. The only changes that have been made to PFC over the last few years are just those that are required to adjust for difference in new PowerBuilder versions (e.g., removal of custom objects that refer to obsolete PowerBuilder classes, updating window class name references, etc).
Q: Is there any limit to catch blocks inside TRY...CATCH...FINALLY...END TRY ?
Not that I’m aware of. There is a limit on the size of pcode that a PowerScript script can generate. That might be the first thing that stops you.
Q: Is there any limit to catch
Not sure what the question was intended to get to.
Q: Is Try/Catch implemented in PB 12.5 both for Classic and .Net?
Yes. The only issue that I’m aware of – and which was mentioned during the webast – is that PowerScript allows returns in finally clauses and C# does not.
Q: Nested trys can give you more granularity in describing where the exception happened.
There is some merit to that argument. I find the need to do that to be more the exception than the norm though. I also don’t tend to write extremely long scripts, but break them up into several functions that get called from a parent routine. That may be why I haven’t had much need to use nested try blocks (some, but not a lot).
Q: Request: When you complete the code sample, if possible, tie it into the Jan 2012 article Powerbuilding with Exceptions. I am still trying to wrap my head around that.
Michael’s main point in that article is that PowerBuilder doesn’t automatically include the stack trace information (object, script, line of code) when you create a custom exception that you often want. And he doesn’t think the developer should have to add it manually each time they throw one. PowerBuilder does provide a PopulateError method that will get you that information. What he does is creates a method that takes the information out of the error object created by the PopulateError method and assigns it to an exception object for you. Since all of your custom exceptions can descend from a common ancestor, it would also be possible to have that method create the custom exception object for you by just passing in the class name. That’s what he’s doing in the second part of the article. The one thing he may be doing that might be throwing you off is called the PopulateError method as a part of the call to his function. It all makes more sense when you see the parts seperately, and then roll them together once you understand the individual pieces. Unfortunately, I finished the code samples later the day of the webcast, and I wasn’t able to get to these questions until over a week later, so the code samples don’t incoporate his technique.
Q: should we define an object (inherit from exception) for every type of errors ?
That’s a judgment call on your part. You could just as easily not use any custom classes at all and just create local objects of throwable or runtimeerror. It all depends on how much you need to differentiate between error causes in your try/catch block.
Q: Is it possible catch embebed SQL exceptions?
Q: Have PB12 the ability to cath sql embebed exceptions?
An embeded SQL error would be communicated to powerBuilder through a negative return code. You might encapsulate the SQL call though so that you had a method on the transaction object that could raise an exception rather than just return a negative SQLCode. I’d even go so far as to recommend moving the embedded SQL into a stored procedure in the database, and then making an RPCFUNC declaration on the transaction object for it. You would still need the wrapper PowerScript function to raise an exception if it failed though.
Q: When an error occurs and you must kill a related running thread, how can you force the destruction of that thread even if the thread is not finished processing?
If you are using shared objects to put code on a seperate thread, you have the option to get a reference to the shared object when you create it. You can use that reference to send a message to the shared object to tell it to cease work.
Q: Even when using TRY/CATCH some errors such as calling a stored procedure that doesn't exist will render a transaction object corrupt. Suggestions?
Corrupt ? It would generate a SQL error with a negative SQLCode. Aside from having to do a rollback I don’t know that it would much other effect.
Q: I have been unable to capture out of memory event as a throwable at the highest level of the application. App still crashes. Any advice?
Two suggestions: 1. There is a PB Resource Monitor utility (PBRESMONxxx.EXE, where xxx is the PB major version number, so 125 for 12.4) that is still shipped with PowerBuilder. It’s in the Shared/PowerBuilder directory. It will warn you when the system is running low on resources. However, it’s been quite some time since I’ve actually seen a need for it. It may have to do with the introduction of garbage collection in more recent versions of PowerBuilder. 2. Write your own routine that your application calls once and a while (perhap on a seperate thread or in the application idle event) that checks system memory and warns the user if its becoming limited. The platform server object in PFC shows how to use the GlobalMemoryStatus method in the windows API to get some of that information.
Q: Here's the answer to the code after finally question: It's the same unless there are RETURN's inside of TRY/CATCH block.
That’s true. Normally there would be a return at the end of the TRY block at a minimum. The finally block is usually the last code in the script.