Foxhound is the better* Database Monitor for SQL Anywhere.
*better: More thorough, more relevant, more effective.
...more Alerts, more All Clears, more details, more control in your hands.


Breck Carter
Last modified: July 10, 1996
mail to: bcarter@bcarter.com



Array Functions

How do I write a function that returns an array? PowerBuilder lets me define structures and other non-scalar data types for the return value but not an array.

Many programming languages restrict function return values to simple "scalar" data types such as integer and string. PowerBuilder allows many other data types such as DataWindow but in fact the return value is still a scalar: a pointer to a more complex object.

You can also type over the return data type to specify your own window type, non-visual user object class or even a structure. But there doesn't appear to be any way to specify an array as a function return type. Not even in PowerBuilder 5.

Or is there? If you're willing to enter The Twilight Zone where simple techniques are undocumented and simple coding errors are diagnosed with General Protection Faults, you can indeed write an array-returning function in PowerBuilder 5. Here's an example of how a user-written global function can be called to add the elements of two array arguments and return the result in a third array:

   integer li_array_1[] = { 1, 2, 3, 4, 5 }
   integer li_array_2[] = { 6, 7, 8, 9, 10 }
   integer li_array_3[]

   integer li_array_4[] = { 1, 2, 3, 4, 5, 6 }
   integer li_array_5[] = { 7, 8, 9, 10, 11, 12 }
   integer li_array_6[]

   // Add array elements 1 to 5.

   li_array_3 = f_sum_arrays ( li_array_1, li_array_2 )

   MessageBox ( "f_sum_arrays [ 1..5 ] ", &
      string ( li_array_3 [ 1 ] ) + ", " &
    + string ( li_array_3 [ 2 ] ) + ", " &
    + string ( li_array_3 [ 3 ] ) + ", " &
    + string ( li_array_3 [ 4 ] ) + ", " &
    + string ( li_array_3 [ 5 ] ) )

   // Different array bounds are OK.

   li_array_6 = f_sum_arrays ( li_array_4, li_array_5 )

   MessageBox ( "f_sum_arrays [ 1..6 ]", &
      string ( li_array_6 [ 1 ] ) + ", " &
    + string ( li_array_6 [ 2 ] ) + ", " &
    + string ( li_array_6 [ 3 ] ) + ", " &
    + string ( li_array_6 [ 4 ] ) + ", " &
    + string ( li_array_6 [ 5 ] ) + ", " &
    + string ( li_array_6 [ 6 ] ) )

   // Nested calls are OK.

   li_array_3 = f_sum_arrays &
           ( li_array_1, &
             f_sum_arrays ( li_array_1, li_array_2 ) )

   MessageBox ( "f_sum_arrays [ nested ] ", &
      string ( li_array_3 [ 1 ] ) + ", " &
    + string ( li_array_3 [ 2 ] ) + ", " &
    + string ( li_array_3 [ 3 ] ) + ", " &
    + string ( li_array_3 [ 4 ] ) + ", " &
    + string ( li_array_3 [ 5 ] ) )

Here's what the three MessageBox calls produce:


The solution lies in the any data type where the word "any" means just that: The variable can take on any data type you want, integer, string, DataWindow, even array.

The any data type was introduced in PowerBuilder 4 to make some kinds of OLE communications possible. Adventurous souls did experiment with its use outside the confines of OLE but soon learned the truth of Powersoft's admonition that it was "a fragile data type that should only be used when absolutely necessary." In other words, "GPFs lurk here!"

With PowerBuilder 5 the any data type has been made more robust. Documentation has also been improved: Instead of just a single mention on page 433 of the "Building Applications" manual it has been given official status in the online Help.

Here's how it's used in the function declaration for f_sum_arrays:

And here's the code for f_sum_arrays:

   integer li_sum_arrays[]
   integer li_counter
   any     lany_return

   if LowerBound ( ai_array_1, 1 ) &
         <> LowerBound ( ai_array_2, 1 ) &
   or UpperBound ( ai_array_1, 1 ) &
         <> UpperBound ( ai_array_2, 1 ) then
      li_sum_arrays [ 1 ] = -1
      lany_return = li_sum_arrays
      return lany_return
   end if

   for li_counter = LowerBound ( ai_array_1, 1 ) &
      to UpperBound ( ai_array_1, 1 )

      li_sum_arrays [ li_counter ] &
         = ai_array_1 [ li_counter ] &
         + ai_array_2 [ li_counter ]

   next

   lany_return = li_sum_arrays
   return lany_return

Three caveats are in order here: First, Powersoft warns that the any data type reduces the level of error checking that PowerBuilder can perform at compile time. If you make a mistake it won't be detected until run time. That's why the code above checks to make sure the two array arguments have the same upper and lower bounds.

Second, an attempt to return li_sum_arrays directly will result in a GPF. You must copy the return value to an any variable and return that variable instead. This little "gotcha" is an example of the Twilight Zone referred to earlier: Some of the rules are documented but others aren't, and early adopters of the any data type must tread carefully.

Finally, Powersoft also warns that overuse of the any data type will make your program run slower because of all the extra run time type checking and conversions that must be performed.


Breck Carter can be reached by phone at (416) 763-5200 or via email at bcarter@bcarter.com.