As well as "simple variables", REXX has arrays. An array is simply one variable that is used to store many pieces of data together. (Think of it like a Data stack, except you have totally random access to any piece of data).

Any ordinary variable name can be turned into the name of an array, simply by appending a dot to the name. For example, to create an array named "MyArray", then MyArray. is the variable name you use to access the array. An array's variable name is referred to as a stem.

An element (ie, field) of an array is accessed by appending an element number or name to the stem. For example, you can have a field named MyArray.1. You can have another field named MyArray.2. Etc. The element number/name itself is called a tail. (ie, Here, "1" and "2" are being used as tails). The stem and tail together are called a compound variable. (ie, The entire name of an array field in REXX is called a "compound variable").

For example, you could have an array with the variable name Days. The first element in the array could be Days.1. The second element in the array could be Days.2. The third element in the array could be Days.3, etc. Days. is the stem of this array, and Days.1, Days.2, and Days.3 are compound variables using this stem. (ie, They are fields of this array).

In fact not only numbers, but other variable names may be used as tails. For example, the first element in the array could be Days.Monday. The second element in the array could be Days.Tuesday. The third element in the array could be Days.Wednesday, etc.

Like with simple variables, an array does not have to be declared before it is used.

/* This script uses an array (stem) named "array."
 * with 3 elements (tails) named 1, 2, and 3
 */
SAY "Input a number"
PULL val
array.1 = val
array.2 = val*val
array.3 = val**3
SAY array.1 array.2 array.3 array.1 + array.2 + array.3
Additional element numbers/names can be appended to create 2-dimensional (or more) arrays. For example, you could have an array with the variable (stem) name Months.. The first element in the array could be Months.January.1. The second element in the array could be Months.January.2, etc. The last element in the array could be Months.December.31. (ie, You could create an array for all 365 days of a year, and have the first tail identify the month, and the second tail identify the day within that month).

Tail name substitution

When you use a simple variable name (rather than a number) for a tail, then something called "tail name substitution" is performed. All this means is that REXX looks up the value of that simple variable, and uses its value for that part of the compound variable name.

For example, let's consider a compound variable named Days.MyDay. When REXX sees this compound name, it notices that the tail (ie, "MyDay") is not a number. So, REXX regards "MyDay" as a simple variable name. REXX therefore substitutes the value of the simple variable named "MyDay". If "MyDay" happens to not have been set to any value, then the default value is MYDAY. (Remember that if a simple variable has not been set to a specific value, then its default value is its own name upper-cased). So, the real name of this compound variable will be Days.MYDAY. That really hasn't changed the compound variable's name much. But let's consider the following two lines:

/* Demonstration of tail name substitution */
MyDay = 'Monday'
Days.MyDay = 'No appointment'
What compound variable are we setting to the value of 'No appointment'? Well, REXX substitutes the tail name "MyDay" with its value, which happens to be the string 'Monday'. So that second line really becomes:
/* Effective result of tail name substitution */
Days.Monday = 'No appointment'
You may be wondering what good tail name substitution is? Well, it can be very useful in a loop, when you use the loop variable as one of the tail names. For example, let's say that we have an array named January. and it has 31 fields named January.1 to January.31 for the 31 days. Here is how you could easily set all 31 fields to the value of 'No appointment':
/* Demonstration of tail name substitution in a loop */
DO i = 1 to 31
   January.i = 'No appointment'
END
For example, the first time in the loop, i will have the value of 1. When REXX sees the compound name January.i, it notices that the tail "i" is a variable name, so it substitutes its value which is 1. The net result is that January.1 is set to the value 'No appointment'. The second time in the loop, i will have the value of 2. Therefore, January.2 is set to the value 'No appointment'. Etc.

So tail name substitution is very useful when you use a loop variable to substitute for a numeric tail.

Tail name substitution is also very useful if you don't know ahead of time which field you need to access. For example, let's say that we have an array named Months. and it has 12 fields named Months.January to Months.December for the 12 months. We'll set the value of each field to how many days are in that month. For example, Months.January = 31, Months.February = 28 (we'll forget about leap years for now), Months.March = 31, etc. Then we'll ask the user for which month he'd like to know how many days are in it. We don't know ahead of time which month he'll choose, so we're going to collect his answer in a simple variable named "answer" and then use that in our compound name so that REXX substitutes what he typed (ie, the value of "answer"):

/* Initialize our array */
Months.January = 31; Months.February = 28; Months.March = 31; Months.April = 30
Months.May = 31; Months.June = 30; Months.July = 31; Months.August = 31
Months.September = 30; Months.October = 31; Months.November = 30; Months.December = 31

/* Ask him for a month, and get his "answer" */
SAY "Type the name of a month"
PULL answer

/* Report how many days in that month */
SAY "There are" Months.answer "days in" answer || '.'
One thing to note is that tail names (but not stem names) are case-sensitive. For example if we substitute the PULL with PARSE PULL, and the user doesn't type a month name all in uppercase (for example, he types "december"), then it won't match any of our array fields. Why? This is because REXX has performed substitution on our tail names above. For example, in the compound name Months.December, REXX substitutes the value of the simple variable named December. But since no such simple variable was set to any particular value, REXX substitutes "DECEMBER". The real name of our array field is Months.DECEMBER and that is not the same as Months.december.

In conclusion, using a variable name as a tail is very useful due to substitution. It allows you to loop through the fields of an array, and also access an array field without prior knowledge of which field your script will be accessing. But you do have to be aware of the implications of substitution, and the fact that tail names are case-sensitive.

If you wish to avoid tail name substitution, then you can always use numbers for tails. Alternately, you can begin your tail name with a numeric character, for example, Months.0January. A legal, simple variable name can't begin with 0 to 9, so REXX no longer sees this as a simple variable name (but you still need to be careful about case-sensitivity because REXX will uppercase all letters in the tail name). Another tactic you can use is to always start your tail names with a character that you would not likely use in any of your simple variable names elsewhere, for example Months.$January. If you never use a simple variable anywhere that begins with a $, then you never need worry about REXX substituting anything but $JANUARY for $January (but again, you still need to be careful about case-sensitivity).


Initializing all fields of an array

You can easily set the value of all fields of an array just by assigning that value to the stem's name.

In a preceding example, we individually looped through all fields of an array named January. and set them to the same value, as so:

DO i = 1 to 31
   January.i = 'No appointment'
END
But an easier, and much less memory intensive way to set all fields to the same value is to assign a value to the stem name itself as so:
January. = 'No appointment'
Now, if you SAY the value of any field that references the array January., then its value will 'No appointment'.

You can later set that field to some other value, but if you ever DROP the field, its value reverts to its compound name uppercased (with any tail name substitution). If you DROP the stem itself, then this automatically DROP's all its fields.

/* Set January.1 to 'Read this book' */
January.1 = 'Read this book'
SAY January.1 /* Displays 'Read this book' */

/* Set all fields to 'No appointment' */
January. = 'No appointment'
SAY January.1 /* Displays 'No appointment' */

/* Set January.1 to 'Do it again' */
January.1 = 'Do it again'
SAY January.1 /* Displays 'Do it again' */

/* DROP January. */
DROP January.
SAY January.1 /* Displays 'JANUARY.1' */

A 2-dimensional example

The following script uses a 2-dimensional array named book.. Each book entry has 3 elements with tail names of author, title, and pub. There can be an unlimited number of book entries, so numbers are used for the first tail. Therefore, book.1.author contains the author of the first book. book.1.title contains the title of the first book. book.1.pub contains the publisher of the first book. book.2.author contains the author of the second book. Etc. The script initializes 2 book entries, asks the user what book number he'd like to see the information for, and prints out that book's author, title, and publisher.

/* This program uses a 2-dimensional array
 * named book with various elements
 */
book.1.author="M. F. Cowlishaw"
book.1.title="The REXX Language, a practical approach to programming"
book.1.pub="Englewood Cliffs 1985"
book.2.author="A. S. Rudd"
book.2.title="Practical Usage of REXX"
book.2.pub="Ellis Horwood 1990"

/* Look up the book that the user indicates. Use a variable
 * to get the element number. Note that we use that variable
 * name when accessing the element number,
 * and thus tail substitution is performed.
 */
SAY "Input a book number"
PULL i
SAY "Author:   " book.i.author
SAY "Title:    " book.i.title
SAY "Publisher:" book.i.pub
As with simple variables, if a particular array element has not been given a value, then its name is used instead. If you run the above script, and enter a 3 for the desired book number (when prompted), then the following is displayed:
Author:    BOOK.3.AUTHOR
Title:     BOOK.3.TITLE
Publisher: BOOK.3.PUB

This is because these 3 elements were never initialized.

You can easily initialize every element of an array using just one instruction by assigning a value to the stem itself. Edit the above script and insert the following instruction after the opening comment:

book.="Undefined"

This gives every possible element of the array the value "Undefined", so that if you again type 3 for the desired book number, the following is displayed:

Author:    Undefined
Title:     Undefined
Publisher: Undefined