Xbasic

Xbasic Arrays

Description

To store a series of data values of the same data type together under the same variable name, declare the variable as an array. Arrays are useful for collecting and processing lists of information. They must be explicitly defined with the DIM statement before they are used. The declaration must include the Array Size which is the maximum number of data elements the array will contain.

For example, the following statements declare an array of character strings holding five elements:

dim names[5] as C
dim names[1..5] as C
dim names[0..4] as C 'dim a 0 based array

Arrays generally contain items of the same type. However, an array can be declared as any type and contain a collection of elements of different types. Assigning a value to an any array element is the same as any other array type. Xbasic sets or adds the value to the array as a pointer variable with a value property, allowing the type of the value to be preserved. To access the value, the value property must be used. For example:

dim a[3] as a
a[1] = "char"
a[2] = 5
a[3] = now()

' Type of all elements in a[] is "P"
?typeof(a[1])
= "P"

?typeof(a[2])
= "P"

?typeof(a[3])
= "P"

' Every element in a[] is a Pointer with a property called value
' that contains the value of the element
?a[1]
= VALUE = "char"

?a[2]
= VALUE = 5

?a[3]
= VALUE = 04/06/2017 09:55:10 03 pm

' The value property is typed to match the original
' assigned values
?typeof(a[1].value)
= "C"

?typeof(a[2].value)
= "N"

?typeof(a[3].value)
= "T"

It is possible to DIM multiple array dimensions in one statement.

dim arr.row[1..10].col[1..5].edited as C
The first element of an array is 1 (unless the array was specifically DIMmed with a different initial index e.g. dim a[0..4] as c).

This array can be used to collect and store a list of five names. The contents of the array elements are assigned like any other variable using the assignment operator ( = ). The number of the element in which you want to put the data must also be supplied. For example:

names[1] = "Henry"
names[2] = "Burt"
names[3] = "Ernie"
names[4] = "Linda"
names[5] = "Cheryl"

Multidimensional Arrays

Xbasic arrays can contain multiple dimensions. For example:

dim a[3,3,3] as C

Arrays of Pointers or "Property" Arrays

You can define an array of pointers. An array of pointers is referred to as a "property array". For example:

dim ar[5] as P
ar[1].mom = "Irene"
ar[1].dad = "Abe"
ar[2].mom = "Arlene"
ar[2].dad = "Kyle"

? ar[1].mom 
= "Irene"

? ar[1].dad 
= "Abe"

? ar[2].mom 
= "Arlene"

? ar[2].dad 
= "Kyle"

ar.SORT("A","mom")
? ar[1].mom 
= "Arlene"

? ar[1].dad 
= "Kyle"

It is useful to visualize a property array like this:

images/chart1.png

The array might have more "columns". For example:

images/chart2.png

In this example, ar[3].kids is 1. To sort the array on the "Kids" element, you would type:

ar.sort("","kids")

Nested Arrays

Xbasic supports nested arrays. For example:

dim row[10] as P
for i = 1 to 10
    dim row[i].col[10] as C
next i

row[1].col[1] = "c"
row[1].col[2] = "b"
row[1].col[3] = "d"
row[2].col[1] = "a"
row[2].col[2] = "x"
row[2].col[3] = "m"

'Sort the elements of the row[1].col array.
'i.e. elements are sorted into this order: b,c,d
row[1].col.sort()

Examining Arrays in the Interactive Window

If you are working with an array in the Interactive window, you can examine the contents of an array by typing ? arrayname in the Interactive window. For example:

dim Names[3] as C
Names[1] = "John"
Names[2] = "Fred"
Names[3] = "Tom"
? Names 
= [1] = "John"
[2] = "Fred"
[3] = "Tom"

Dynamic Arrays

Alpha Anywhere supports a special syntax that allows you to automatically insert elements at the end of an array without having to specify the array index. The [] operator can be used to simultaneously append a new entry in an array and assign it a value using the = operator. Whether resizing also happens when deleting an entry depends on using the <array>.setDynamic() method. For example:

dim cities[1] as C
'add a new entry to the array by omitting the array index
cities[] = "boston"

? cities.SIZE() 
= 1.000000

? cities 
= [1] = "boston"

cities[] = "chicago"
? cities.size() 
= 2.000000

? cities 
= [1] = "boston"
[2] = "chicago"

If the last value of the array is "empty", Alpha Anywhere will not append a new entry whe [] is used. For example, consider the following array:

dim numArr[0] as n
for i = 1 to 10
    numArr[] = 0
next i

? numArr.size()
= 1

Alpha Anywhere interprets the value of "0" as "empty" for numeric arrays. Instead of creating an array of 10 entries with a value of 0, numArr is an array with one empty entry. If the desired result is an array of 10 values, all set to zero, you disable recycling by calling <array>.set_recycle() with a value of .f. or using the <array>.append() method:

dim numArr2[0] as n
numArr2.set_recycle(.f.)
for i = 1 to 10
    numArr2[] = 0
next i

? numArr2.size()
= 10

dim numArr3[0] as n
for i = 1 to 10
    numArr3.append()
next i

? numArr3.size()
= 10

An empty string "" is considered an "empty" value for a character array.

Dynamic Property Arrays

Property arrays support the [] syntax. The [..] can be used to add properties to the last element in the property array.

dim a[1] as P
a[1].name = "Fred"
a[1].city = "Boston"
a[1].age = 23
a[].name = "Tom"
a[..].city = "NY"
a[..].age = 35

? a.dump_properties("Name|city|age")
= Fred|Boston|23
Tom|NY|35

In the script, a[].name = "Tom" adds array element number 2. a[..]. city = "NY" adds "NY" to the newly created array element (i.e. number 2).

While this syntax is supported, it is not a recommended best practice to use [] and [..] to dynamically append elements to a property array. And here's why.

If you forget to use [..] to add properties and instead use [], you can end up in the following scenario:

dim a[0] as p
a[].name = "Fred"
a[].city = "Boston"
a[].age = 23
a[].name = "Tom"
a[].city = "NY"
a[].age = 35

? a.dump_properties("Name|city|age")
= Fred||
|Boston|
||23
Tom||
|NY|
||35

Instead of creating two array entries with a name, city, and age property, six array entries were created with either a name, city, or age property.

To avoid this issue, use <array>.append() instead. The following is the recommended approach to dynamically populating a property array:

dim a[1] as P
a[1].name = "Fred"
a[1].city = "Boston"
a[1].age = 23

i = a.append()
a[i].name = "Tom"
a[i].city = "NY"
a[i].age = 35

? a.dump_properties("Name|city|age")
= Fred|Boston|23
Tom|NY|35

Typing Property Arrays

This example shows another common technique used with Property arrays:

type Family
   Mother as c 
   Father as c 
end type

'All new array entries will now automatically have a 'Mother' and 'Father' property.
'Notice that the initial array size is DIMmed as 0
dim a[0] as {Family}

i = a.append()
a[i].Mother = "Irene"
i = a.append()
a[i].Mother = "Ann"
a[i].Father = "Bernard" 

?a[1].Father 
= ""

?a[2].Father 
= "Bernard"

a[i].age = 35 

? a[2]
= age = 35
FATHER = "Bernard"
MOTHER = "Ann"

A type can be used to define the default set of properties that should be added when a new entry is added to the property array. See Xbasic Types to learn more about types.

Implicit Array Declaration

When you use the [] syntax to add entries to an array, the array does not need to be DIMmed in advance. For example:

b[] = "alpha"
b[] = "beta"
?b.size()
= 2

The same applies to property arrays:

workweek[].day = "Monday"
workweek[].day = "Tuesday"
workweek[].day = "Wednesday"
workweek[].day = "Thursday"
workweek[].day = "Friday"
? workweek.size()
= 5
Prefer to use <array>.append() when working with dynamic property arrays.

Dynamic Array Sizing

When you delete entries from an array, the array size does not change unless dynamic sizing is enabled. Dynamic sizing can be enabled by declaring the array with a size of zero (e.g. dim arr[0] as p) or by calling the <array>.set_dynamic() method and passing a value of .t.. When dynamic sizing is enabled, deleting an entry from an array will resize the array. The following Interactive window session demonstrates an array where dynamic sizing has not been enabled because the array was declared with a size greater than zero:

dim array[3] as c
array[1] = "alpha"
array[2] = "beta"
array[3] = "gamma"
?array.size()
= 3 

array.delete(2,1)
?array.dump() 
= alpha gamma 

?array.size() 
= 3

If we repeat this exercise and enable dynamic sizing, the array will decrease in size when the delete() method is called on the array:

dim array[3] as c
array.set_dynamic(.t.)
array[1] = "alpha"
array[2] = "beta"
array[3] = "gamma"
?array.size()
= 3 

array.delete(2,1) 
?array.dump() 
= alpha 
gamma 

?array.size() 
= 2

The <array>.set_dynamic() method can be used to turn on/off the dynamic sizing property of an array. The <array>.get_dynamic() method can be used to determine the state of an array's dynamic sizing property.

If you DIM an array with a size of 0 (and then populate the array using the [] syntax or <array>.append()), the dynamic sizing property is automatically assumed to be set to .t.. For example:

dim array[0] as c
array[] = "alpha"
array[] = "beta"
?array.size()
= 2 
array.delete(2,1) 
?array.size() 
= 1

This shows that an array DIMmed with an initial size of 0 defaults to dynamic properties on, whereas an array DIMmed with non-zero size defaults to dynamic properties off.

dim arr1[0] as p
dim arr2[1] as p
? arr1.get_dynamic() 
= .T.
? arr2.get_dynamic() 
= .F.

Passing Arrays to Functions

When you pass an array to a function, the receiving function defines the argument as a pointer.

Dim a[5] as C
a[1] = "a value"
my_function(a)

function my_function as V (arr as P)
    ui_msg_box("Array Value", arr[1])
end function

DIMming Arrays with Default Values

When you DIM a new array, you can specify a default value for each array item. This is especially useful when DIMming arrays for use with .Net code:

dim sb[6] as system::Text::StringBuilder = new system::Text::StringBuilder(1024)
? sb[1].capacity
= 1024
? sb[2].capacity
= 1024
...


dim nums[6] as n = rand()
? nums
= [1] = 0.50457763671875
[2] = 0.172149658203125
[3] = 0.35626220703125
[4] = 0.722320556640625
[5] = 0.053955078125
[6] = 0.99090576171875


dim strs[6] as c = Rand_String(6+int(rand()*10))
? strs
= [1] = "skqesxkb"
[2] = "trzafnjrijy"
[3] = "ozzaofjmcboht"
[4] = "lqletpztxqkhan"
[5] = "xilavqnlvmofpt"
[6] = "plbdelndbfhsgsc"

Creating Arrays of Objects Using <array>.clone()

The <array>.clone() method can be used to assign an object into a property array initially declared as a p type.

This example creates an array containing five SQL::TableInfo objects.

dim ti as SQL::TableInfo
dim arr[5] as P
arr[1] = ti
for i = 2 to 5
    arr[i] = ti.clone()
next i

Initialize Array From Table

The <array>.initialize_from_table() method allow you to optionally append to an existing array (instead of always initializing it), and to specify a list of fieldnames (rather than populating the array with every field in the source table). The array will also be resized correctly based on the number of records that satisfy the filter criteria if the dynamic sizing is enabled for the array.

For example, here is an Interactive window session using the Alphasports sample database:

'Start with empty array (automatically dynamic)
dim arr[0] as p

'Pull in NY records from Customer table...
arr.initialize_from_table("customer","bill_state_region='NY'","",.f.)
?arr.size()
= 8

'Now, pull in MA records from the Customer table. Notice that the append flag is set to TRUE so that records are added to the end of the array.
arr.initialize_from_table("customer","bill_state_region='MA'","",.t.)
? arr.size()
= 29

In this example, only selected columns are loaded into the array.

dim fieldList as c 
fieldList = <<%txt%
CUSTOMER_ID
COMPANY
FIRSTNAME
LASTNAME
%txt%

dim arrlim[0] as p
arrlim.initialize_from_table("customer","bill_state_region='NY'","",.f.,fieldlist)
? arrlim2
= COMPANY = "Alpha Software New York"
CUSTOMER_ID = "00000010"
FIRSTNAME = "Bryan"
LASTNAME = "Bloomberg"

References To Arrays

When an xbasic function is returning an array type, or being passed array types as an argument, this has been done by declaring the type as 'P'.

As of Alpha Anywhere Version 4.4.4, there is syntax to represent returning and array, or passing an array back from a function. A "[]" Suffix after the type represents an 'array of' the type.

The following Example shows methods

Example of a function returning a array of character strings. In this example, the method takes a passed in character string of comma separated words, and converts this into an array of 'words'.

function asAnArray as c[](commaList as c)
	commaList = comma_to_crlf(commaList)
	asAnArray.resize(line_count(commaList))
	asAnArray.initialize(commaList)
end function

Example of a function consuming an array of character strings. This example converts the array of words into a single string containing a comma separated words.

function asText as c(arr as c[])
	asText = crlf_to_comma( arr.dump() )
end function

Example calling the methods that return an array, and produce a string from the array.

arr = asAnArray("one,two,three")
? arr.size()
= 3

? arr.dump()
= one
two
three
? asText(arr)
= "one,two,three"

In addition to the built in xbasic types (c[] for character array, n[] for numeric array etc) A reference to an array if a user defined type can be defined as well.

Starting with a class class definition of a 'point' which has x and y members.

define class mynamespace::point
   dim x as n
   dim y as n
end class

A Function returning an array of points, that parses as simple format string to create the array.

function ToPointArray as mynamespace::point[](points as c)
	points = strtran(points,";",crlf())
	ToPointArray.initialize_properties("x,y",points)
end function

From the Interactive window, calling function returning array of class instances:

pa = ToPointArray("1,1;2,2;1,2")
? pa[1]
= x = 1
y = 1

? pa[2]
= x = 2
y = 2
? pa[3]
= x = 1
y = 2

See Also