PowerBuilder Design Standards - GOTO Statement Usage
The use of the GOTO statement is considered to be an extremely poor programming
practice. My father, who taught computer science in college, would
fail students for using it because of the resulting spaghetti code. I
have never used GOTO
in a programming language until PowerBuilder.
Except for the example given below, I fully support
avoiding the use of the GOTO function.
PowerBuilder is one of very few languages that lacks a well-designed and
implemented TRY..FINALLY..END
programming
structure for catching thrown expections. Delphi, PL/SQL, Visual Basic,
and others all have this construct. The only way that I found to be
do this in PowerBuilder is to use the GOTO syntax.
The purpose of a TRY..FINALLY..END
code block is to make sure that regardless of what happens between the
TRY..FINALLY
the code between the
FINALLY..END
block gets executed.
Simple Summary
Delphi (Similar code is used for PL/SQL and Java) |
PowerBuilder |
Try
Screen.Cursor := crHourGlass;
xxx = Create yyy
<< Processing ...>>
Finally
Destroy(s)
Screen.Cursor := crDefault;
Result := li_return_code
End;
|
<< No Equivalent to "Try" >>
SetPointer()
xxx = Create yyy
<< Processing ...>>
If (li_return_code <> 1) Then
GOTO Destroy_Dynamic_Objects_and_Exit
End If
<< No Equivalent to "Finally" >>
GOTO Destroy_Dynamic_Objects_and_Exit:
Destroy(NVOs and Datastores)
SetPointer(Arrow!)
Return li_return_code
|
Problematic Code |
Reliable, Easy to Read, Easily Maintained Code |
integer li_datastore_index, & li_upperbound
Datastore lds_temp[]
lds_temp[1] = Create Datastore
lds_temp[1].<< Rest of the Datastore creation code >>
lds_temp[2] = Create Datastore
lds_temp[2].<< Rest of the Datastore creation code >>
lds_temp[3] = Create Datastore
lds_temp[3].<< Rest of the Datastore creation code >>
...Processing with lds_temp[1]...
If (lb_okay_to_continue) Then
...Processing with lds_temp[2]...
If (lb_okay_to_continue) Then
// If Business Rule xxx violated, Stop and
// Return Error code
...Processing with lds_temp[3]...
Else
...all the Destroy code again (see bottom)...
Return
End If
If (lb_okay_to_continue) Then
...More Processing with lds_temp[2]...
Else
...all the Destroy code again (see bottom)...
Return
End If
If (lb_okay_to_continue) Then
...More Processing with lds_temp[3]...
End If
End If
// Datastore Destroy Logic
li_upperbound = UpperBound(lds_temp[]) For i = 1 to li_upperbound If IsValid(lds_temp[i]) Then
Destroy(lds_temp[i]) End If Next
Return li_return_code
|
integer li_datastore_index, & li_upperbound
Datastore lds_temp[]
lds_temp[1] = Create Datastore
lds_temp[1].<< Rest of the Datastore creation code >>
lds_temp[2] = Create Datastore
lds_temp[2].<< Rest of the Datastore creation code >>
lds_temp[3] = Create Datastore
lds_temp[3].<< Rest of the Datastore creation code >>
...Processing with lds_temp[1]...
If (lb_okay_to_continue) Then
li_return_code = -1
GOTO Destroy_Dynamic_Objects_and_Exit
End If
...Processing with lds_temp[2]...
If (lb_okay_to_continue) Then
li_return_code = -2
GOTO Destroy_Dynamic_Objects_and_Exit
End If
...Processing with lds_temp[3]...
If (lb_okay_to_continue) Then
li_return_code = -2
GOTO Destroy_Dynamic_Objects_and_Exit
End If
...Processing with lds_temp[2]...
If (lb_okay_to_continue) Then
li_return_code = -2
GOTO Destroy_Dynamic_Objects_and_Exit
End If
...Processing with lds_temp[3]...
If (lb_okay_to_continue) Then
li_return_code = -2
GOTO Destroy_Dynamic_Objects_and_Exit
End If
GOTO Destroy_Dynamic_Objects_and_Exit:
li_upperbound = UpperBound(lds_temp[]) For i = 1 to li_upperbound If IsValid(lds_temp[i]) Then
Destroy(lds_temp[i]) End If Next
Return li_return_code
|
Summary : Let's say that "Business Rule xxx" is violated
and we have 20 datastores rather than just three. The
lb_okay_to_continue logic gets confusing and quickly reduces
the readability of the code. It may even introduce errors because we
may not have a linear computation process, but it is accidentally being treated
as one.
Issue : The developer needs the ability to
jump to the end of a script to handle the destroying
of any NVOs and Datastores (within scope, of course) to prevent memory leaks.
Fortunately (or unfortunately) GOTO provides that functionality for
PowerBuilder. |