Welcome!

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

Related Topics: PowerBuilder, .NET

PowerBuilder: Article

Power Building with Exceptions

It’s a matter of code elegancy

To pass errors from functions outward, throw exceptions instead of returning an error code like -1. That's implemented by filling the "Throws:" field in the function's header (signature) with the class Exception or its descendant. When the exceptions mechanism is used, calls to functions look very simple:

uf_do_something()

As you see, there is no terrible code impurities like

if uf_do_something() = -1 then return -1

or even

li_rc = uf_do_something()
if li_rc = -1 then return -1
anymore!

The tradition of returning a success/failure code come from ancient times when exception throwing mechanism didn't exist yet in PowerBuilder, but there's no need to use horses in the automobile era. We still check code returned by built-in PB functions, as well as in legacy application code, but be a modern person and write new code.

The Art of Exceptions Propagation
The rule of using exceptions in multi-level, multi-branch call hierarchies is simple: if you have a chain of nested function calls (uf_1 calls uf_2; uf_2 calls uf_3; uf_3 calls uf_4; etc.) then the try...catch block usually appears only in the outermost function (uf_1) - the calling hierarchies' root, decorating the calling to uf_2; functions uf_2, uf_3 and uf_4 usually don't have their own try...catch blocks - they only transfer exceptions outward. Even more - the root function also can exist without the try...catch block, passing the exception out. A good example of this is a controller NVO in which a root public function, which will be called from another script(s) of your application, calls subsidiary private functions of the NVO. In this situation, the exceptions, having come to the root function from the dark ocean depths of the calls hierarchy, is thrown out by the root function of the NVO instead of returning -1. That will add elegancy to the script that consumes your service, for example, it can be a button's Clicked event - that is really "the first station." So, calling the NVO's public function from it must be surrounded with try...catch.

Of course, the not-root functions are not prohibited from having their own try...catch blocks too, but it's a pretty rare practice that happens if they need to process an exception in their special way and then re-throw it.

(To Be) or (Not to Be)?
Calling a function that throws an exception requires special processing in the calling script. Fortunately, the rule is simple: if script A calls script B and script B throws an exception, then script A has two, and only two, choices:

  • To process (i.e., to catch) the exception. For that, script A must surround the call to script B with a try...catch block.
  • Not to process the exception (i.e., to pass it outwards by filling the field "Throws:" in the header of script A). In that case an outer script, calling script A, will bother deciding what to do with the exception.

You don't have to learn this rule: the compiler forces you to perform at least one of the described actions, so you have no chance to unintentionally "interrupt current" in nested, multi-level call chains by forgetting to add throwing an exception to the function's signature.

What Is Wrong with the Built-In PB Exceptions?
It's not a big deal to throw an exception in PowerBuilder 8 or later but, IMHO, three very important conditions must be taken into account:

  1. The error message, describing the problem, should display the class and the script where the problem occurred.
  2. That info must not be typed by the developer each time manually - it should be populated automatically.
  3. The code, throwing the exception, must be compact - in fact, it's a piece of technical code, embedded into business code, so it shouldn't be longer than one line. Imagine if your script throws a number of exceptions, and each time an exception object has to be created, populated and thrown... You'll hardly see the business logic behind all that technical garbage.

The following solution is absolutely not acceptable:

Exception        l_ex

try

[...code...]
if [condition of Problem 1] then
l_ex = create Exception
l_ex.SetMessage("[description of Problem 1] in function uf_XXX of class n_YYY")
throw l_ex
end if

[...code...]
if [condition of Problem 2] then
l_ex = create Exception
l_ex.SetMessage("[description of Problem 2] in function uf_XXX of class n_YYY")
throw l_ex
end if
catch(Exception e)
MessageBox("Error", e.GetMessage())
end try

More Stories By Michael Zuskin

Michael Zuskin is a certified software professional with sophisticated programming skills and experience in Enterprise Software Development.

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.