Site hosted by Angelfire.com: Build your free website today!
 

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.