Yazoo ---> Online Help Docs ---> Yazoo scripting

Arrays

If we were to try to program in Yazoo using only the methods described in the last section, one of the things that we would still find very difficult would be working with large amounts of memory. Simply setting aside, say, a megabyte of integer storage would require the order of a herculean megabyte of Yazoo code. The reason is that each variable, and each member of a composite variable, is considered to be a unique object, so the user has to give each one an individual name to distinguish it. But for cases when individuality is unimportant, we can make do with a blander structure called an array: a homogeneous set of identical elements that are distinguished only by their positions in the structure.

The specific element of an array is specified by one or more indices. An array whose elements are referenced by a single index is basically a list; an array with two indices (a two-dimensional array) can be thought of as a table; etc. One conjures up a particular element of an array by writing each of its indices in square brackets [...] immediately (no space) after the name of the array. To create the array in the first place, one just defines the maximum index for each dimension of the array using the normal define operator. Some basic manipulations on arrays are demonstrated below.


    weeks := 50, years := 5
    HoursWorked[weeks * years][5] :: ulong        | defines a 250 x 5 array
    HoursWorked[1][1] = HoursWorked[1][2] = 8     | writes some elements
    HoursWorked[1][2, 4] = HoursWorked[1][1, 3]   | copies a block of elements
    HoursWorked[2] = HoursWorked[1]               | copies a whole row
   

There are a few tricks here: the fourth line shows how one can, sometimes, work with whole groups of indices (the conditions are given below), and the fifth line demonstrates that a partially-indexed array can be thought of as an array in its own right of lower dimension. This example shows that a whole array or chunk of an array can be manipulated as if it were a single variable (which is not too surprising since the same is true for composite variables).

Arrays, like variables, can also be defined with more complex types.


    TimeCard[52][5] :: { Hour[2] :: ulong, Minute[2] :: ulong }  | time in, out
   

Then we access the array elements by alternating named and indexed members.


    TimeCard[10][3].Hour[2] = 17    | leave at 5 PM
   

One unfortunate qualifier is that there are difficulties when the type-definitions of an array's elements has non-define operations in it. For example,


    TimeCard[52][5] :: { Hour :: ulong, Hour = 2 }
   

executes similarly to


    TimeCard[52][5] :: { }
    TimeCard[*][*].Hour :: ulong   | legal
    TimeCard[*][*].Hour = 2        | illegal
   

where [*] represents all indices of a given dimension. This doesn't work because equate cannot (at present) copy data from a constant over to multiple array indices. Some of these restrictions may be loosened in a future version of Yazoo.

The user can access multiple indices at once by specifying the first and last elements of that range; e.g. my_array[4, 7] refers to indices 4, 5, 6 and 7. However, there are restrictions when working with multi-dimensional arrays, having to do with the way Yazoo stores these arrays in its (one-dimensional) memory. Internally, a multi-dimensional array is stacked so that the last index increments over consecutive elements in memory; adjacent blocks are determined by the next-to-last index; etc. So for the array a[2][3] :: ulong, the order of elements is [1][1], [1][2], [1][3], [2][1], [2][2], [2][3]. The rule is that any block of an array the user accesses must be contiguous in memory. Some examples of statements that obey or violate this rule are given below.


    grid[5][10] :: { score :: double, units[4] :: ulong }
   
    print(
       grid[2, 3]                   | legal
       grid[4, 5][1, 10]            | legal
       grid[1, 5][4]                | will cause error
       grid[1, 5][1, 10].units      | legal
       grid[1, 5][1, 10].units[1]   | will cause error
    )
   

In this last example every case of multiple array indices was a token. We could have made the token explicit by an alias of the form:


    grid_tok[*] := @grid[2, 3]
   

We can also copy data directly over ranges of indices. However, as mentioned above, we cannot copy inlined constants to multiple array indices. Thus


    grid[2, 3].score = 0
   

is illegal; we have to set the score values one by one. The same rule usually prevents the define-equate operator from working in array definitions, as in:


    array[10] :: { score := 0 }   | the equate part of := won't work
   

Thorny issues arise in abundance when one tries to run arrays of functions:


    f[10] :: {
       counter :: ulong
       num :: double
       
       code
       
       for counter in [1, 5]
           print(num)
       endf
    }
   
    f[*]()       | here we have an error
   

Here the error happens in the for statement: Yazoo can't increment counter because counter is an array. To get around this problem, try defining counter outside of f(). If we do this then f[*]() will work. However, attempting f[3]() still won't work, for the (admittedly technical) reason that the argument inside the print() function cannot create a token for num in just one element of the f[] array, in the same way that one cannot form the alias f[3].al := @num.

(It must be noted that the delete command, which will be described presently, is slightly more relaxed about this rule. Since delete keeps track of the last index of its argument separately from the rest, it only requires that the preceding steps are contiguous in N-1-dimensional array space. So, referring again to this past example, the third argument to print() would have been legal had it instead appeared after a delete operator.)

One handy shortcut for accessing all the elements of a given array dimension is the `wildcard' [*] operator. In the example above, the fourth line in the arguments of print() could have been written


       grid[*][*].units
   

An array defined with [*] defaults to size 0. Be aware that this wildcard operator can automatically rescale the array when used to the left of an equate or forced-equate statement, as explained in the next section.

One caveat to bear in mind when passing subsets of arrays is that, depending on the notation used, the sub-array may get collapsed along one or more dimensions. That is because, as Yazoo steps across two or more consecutive array dimensions, it only counts the total number of elements being referenced while losing track of how they factor along the dimensions, and at the end of the day it just assumes they form a one-dimensional list. For example, pretend we have the following function arguments:


    grid
    grid[*]
    grid[*][*]
   

The first line returns a two-dimensional array. The second line returns the one-dimensional list of all `rows' of the table, each of which has a further set of indices over the columns, so it is also effectively a table. The third line returns the entire array rearranged into a one-dimensional list. If we are at the command prompt we can mprint() each of these three lines, and that will confirm that the first two expressions print out as proper tables whereas the third writes out as a long list.


Prev: This and that   Next: Resizing


Last update: July 28, 2013

Get Yazoo scripting language at SourceForge.net. Fast, secure and Free Open Source software downloads