PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder

PowerBuilder: Article

The (New) Exception Call Stack Part 1 Of 2

The (New) Exception Call Stack Part 1 Of 2

In this issue Tim Nesham covers in-depth the TRY-CATCH-FINALLY block, which is new to PowerBuilder 8. But what is really happening behind the scenes? This article will give some historical background on PowerBuilder, but will also focus on PowerBuilder exception handling.

When I first learned Java, I was amazed at how much it resembled PowerBuilder. The two languages are strikingly identical in how they implement inheritance and polymorphism. Over the past month, I have previewed PowerBuilder 8. Guess what? Power-Builder is starting to look like Java.

What first caught my eye is how PowerBuilder 8 handles runtime errors. Before I discuss the new features, I would first like to cover how previous versions of PowerBuilder handle runtime errors. Let's begin with a history lesson.

Error Event
This event is fired if a runtime error occurs on a Connection, JaguarORB, DataWindow, or OLE control. Since this event gives us many arguments to work with, these arguments tell us the nature and the severity of the error. Code is placed in this event to handle the error. If the error is not severe, perhaps we ignore it. Maybe we let the user off the hook with a message box - a simple slap on the wrist. If no code exists in this event, then the error structure information is used to populate the global error variable and the SystemError event on the Application object is triggered.

SystemError Event
In the SystemError, event code can be placed to handle the runtime error. As in the Error event, we can choose what we want to do. If no code is placed in the SystemError event, the application goes into crash-and-burn status.

So what's the big deal? Well, the problem with the "old way" is that error handling occurs far from the source. This can really limit how we can handle runtime errors. PowerBuilder 8 changes all this with "exception" handling. Exception handling allows programmers to deal with runtime errors, right at the source.

What's an Exception?
The term exception is shorthand for the phrase "exceptional event." It can be defined as follows: An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions. Many kinds of errors can cause exceptions - problems ranging from serious hardware errors, such as a hard disk crash, to simple programming errors, such as trying to access an out-of-bounds array element. When such an error occurs within a PowerBuilder script, PowerBuilder creates an exception object and hands it off to the runtime system.

The exception object contains information about the exception, including its type and the state of the program when the error occurred. The runtime system is then responsible for finding some code to handle the error. In new terminology, creating an exception object and handing it to the runtime system is called throwing an exception.

After a method throws an exception, the runtime system leaps into action to find someone to handle the exception. The set of possible "someones" to handle the exception is the set of methods in the call stack of the method where the error occurred. The runtime system searches backward through the call stack, beginning with the method in which the error occurred, until it finds a method that contains an appropriate exception handler.

An exception handler is considered appropriate if the type of exception thrown is the same as the type of exception handled by the handler. Thus the exception bubbles up through the call stack until an appropriate handler is found and one of the calling methods handles the exception. The exception handler chosen is said to catch exception.

The interesting premise of this technology is that Java handles runtime errors (now called exceptions) the same way.

By using exceptions to manage errors, PowerBuilder has new advantages over traditional error management techniques:

  • Advantage 1: Separating Error Handling code from "regular" code
  • Advantage 2: Propagating errors up the call stack
  • Advantage 3: Grouping error types and error differentiation
Advantage 1: Separating Error
Handling Code from "Regular" Code

In traditional PowerScript, error detection, reporting, and handling often lead to confusing spaghetti code. For example, suppose you have a function that reads an entire file into memory. In pseudo-code, your function might look something like this:

of_readfile (
open the file;
determine its size;
allocate that much
read the file into
close the file;

At first glance, this function seems simple enough, but it ignores all of these potential errors:

  • What happens if the file can't be opened?
  • What happens if the length of the file can't be determined?
  • What happens if enough memory can't be allocated?
  • What happens if the read fails?
  • What happens if the file can't be closed?
To answer these questions within your function, you'd have to add a lot of code to do error detection, reporting, and handling. Your function would end up looking something like Listing 1.

With error detection built in, your original seven lines have been inflated to 24 lines of code - a bloat factor of almost 400%. Worse, there's so much error detection, reporting, and returning that the original seven lines of code are lost in the clutter. And, worse yet, the logical flow of the code has also been lost in the clutter, making it difficult to tell if the code is doing the right thing. (Is the file really being closed if the function fails to allocate enough memory?)

It's even more difficult to ensure that the code continues to do the right thing after you modify the function three months after writing it. Many programmers "solve" this problem by simply ignoring it - errors are "reported" when their programs crash.

Now we have an elegant solution to the problem of error management: exceptions. Exceptions enable you to write the main flow of your code and deal with the, well, exceptional cases elsewhere. If your function used exceptions instead of traditional error management techniques, the pseudo-code would look something like that in Listing 2.

Note that exceptions don't spare you the effort of doing the work of detecting, reporting, and handling errors. What exceptions do provide is the means to separate all the grungy details of what to do when something out-of-the-ordinary happens from the main logic of your program. In addition, the bloat factor for error management code in this program is about 250% - compared to 400% in the previous example.

Advantage 2: Propagating Errors Up
the Call Stack

A second advantage of exceptions is the ability to propagate error reporting up the call stack of methods. Suppose that the readfile method is the fourth method in a series of nested method calls made by your main program: method1 calls method2, which calls method3, which finally calls readfile.

method1  (
call method2;
method2  (
call method3;
method3  (
call readfile;

Suppose also that method1 is the only method interested in the errors that occur within readfile. Traditional error notification techniques force method2 and method3 to propagate the error codes returned by readfile up the call stack until the error codes finally reach method1 - the only method that is interested in them (see Listing 3).

PowerBuilder searches backward through the call stack to find any methods that are interested in handling a particular exception. A function can "duck" any exceptions thrown within it, thereby allowing a method farther up the call stack to catch it. Thus only the methods that care about errors have to worry about detecting errors.

method1  {
call method2;
catch (exception)  {
end try
method2 throws exception  {
call method3;
method3 throws exception  {
call readFile;

However, as you can see from the pseudo-code, ducking an exception does require some effort on the part of the "middleman" methods. Any checked exceptions that can be thrown within a method are part of that method's public programming interface and must be specified in the throws clause of the method. Thus a method informs its callers about the exceptions that it can throw, so that the callers can intelligently and consciously decide what to do about those exceptions. Note again the difference in the bloat factor and code obfuscation factor of these two error management techniques. The code that uses exceptions is more compact and easier to understand.

Advantage 3: Grouping Error Types
and Error Differentiation

Often exceptions fall into categories or groups. For example, you could imagine a group of exceptions, each of which represents a specific type of error that can occur, when manipulating an array: the index is out of range for the size of the array, the element being inserted into the array is of the wrong type, or the element being searched for is not in the array.

Furthermore, you can imagine that some methods would like to handle all exceptions that fall within a category (all array exceptions), and other methods would like to handle specific exceptions (like the null object references, please).

Because all exceptions that are thrown within PowerBuilder are first-class objects, grouping or categorization of exceptions is a natural outcome of the class hierarchy. PowerBuilder exceptions must be instances of Throwable or any Throwable descendant.

Throwable Object
A new Throwable object is the ancestor for all user-defined exceptions and system exceptions. There are two other system object types, RuntimeError and Exception, derived from Throwable.

PowerBuilder runtime errors are now placed within the RuntimeError object type. When any system-related runtime error occurs, we can use this class to see what's up. For more specific error handling, the RuntimeError object has its own descendants.

One of the descendants of RuntimeError is the DivideByZeroError object type that is thrown by the application whenever this event occurs. This allows the handling of this type of error explicitly and immediately. Other descendants of RuntimeError include:

  • NullObjectError
  • DWRuntimeError
  • OLERuntimeError
  • CORBASystemException
PowerBuilder throws the above types that descend from RuntimeError when the appropriate runtime error occurs. These can be caught in a TRY-CATCH-FINALLY block (which I will soon discuss).

The PowerBuilder class Exception is also derived from Throwable and is typically used as an ancestor object for user-defined exception types. It is the root class for all checked exceptions. In addition to system exceptions, you can create your own. User-defined exception handling is beyond the scope of this article. I will discuss user-defined exceptions next month.

What's Next?
Now that you understand what exceptions are and the advantages of using exceptions in your PowerBuilder programs, it's time to learn how to use them.

When trapping runtime errors within PowerScript use the Try-Catch block. Before I show you how this block works, it will be a good idea to show you some pre-PowerBuilder 8 code that doesn't have any exception handling. See the code example in Listing 4.

The above code has at least three major problems. First of all, while we are performing division, what happens if we divide by zero? Furthermore, what happens if the window w_window is not currently open? Finally, the last line of code is trying to access an array element that does not exist. Does this code compile? You betcha. But there are at least three runtime errors that can occur. In this legacy piece of code, error handling would have to take place in the Application object's SystemError event. But not anymore.

These runtime errors can be caught in a TRY-CATCH. As you will see the syntax is straightforward and easy to use. In PowerBuilder 8, the code would look like that in Listing 5.

This is the simplest syntax of a TRY-CATCH. It works exactly like an IF statement. The code in the TRY is treated specially. If a runtime error occurs, PowerBuilder notes the type of runtime error that has occurred and looks to see if you "caught" it. If so, the code within the CATCH block is fired. Does this make sense?

In the last portion of the code in Listing 5, we are catching a RuntimeError (which is the generic way of catching ALL runtime errors). Since a runtime error occurred in our TRY block - rather than the user crashing and burning - the user is shown a friendly message and we all can breathe a sigh of relief. Can multiple lines exist in a TRY-CATCH? Yes. Take the following code example:

ls_names[11] = "Caroline"
st_result.text = String (li_result)
w_window.visible = FALSE
catch (RuntimeError e3)
messagebox ("Error",e3.getMessage())
end try

In this example, if any runtime error occurs within the TRY block, the code in the CATCH is fired. Here we are displaying the nature of the system error via the getMessage method on the RuntimeError class. What can you do with an exception once you've caught it? It's really up to you.

  • Fix the problem and try again.
  • Do something else instead.
  • Exit the application with HALT CLOSE.
  • Rethrow the exception.
  • Throw a new exception.
  • Return a default value.

Catching Multiple Exceptions
In the above example, we have a TRY-CATCH block for each individual operation we wanted to do. It worked just fine, but there is even a better way. You may be wondering if you are allowed to catch multiple exceptions. Well, you can. The example in Listing 6 catches multiple exceptions.

In this code, if multiple blocks match the exception type, the first block that matches the type of the exception catches it.

Next Month
This should get you going with exception handling. Since there is so much more to talk about, next month I'll give you the lowdown on advanced exception-handling techniques as well as how to write your own exception classes.

More Stories By Bob Hendry

Bob Hendry is a PowerBuilder instructor for Envision Software Systems and a frequent speaker at national and international PowerBuilder conferences. He specializes in PFC development and has written two books on the subject, including Programming with the PFC 6.0.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.