Assignments and Symbols

A variable is an object whose value can change during the running of a Rexx program. The process of changing the value of a variable is called assigning a new value to it. The value of a variable is a single object. Note that an object can be composed of other objects, such as an array or directory object.

You can assign a new value to a variable with the ARG, PARSE, PULL, or USE instructions, the VALUE built-in function, or the but the most common way of changing the value of a variable is the assignment instruction itself. Any clause in the form

symbol=expression;

is taken to be an assignment. The result of expression becomes the new value of the variable named by the symbol to the left of the equal sign.

Example:

/* Next line gives FRED the value "Frederic" */
Fred="Frederic"

The symbol naming the variable cannot begin with a digit (0-9) or a period.

You can use a symbol in an expression even if you have not assigned a value to it, because a symbol has a defined value at all times. A variable to which you have not assigned a value is uninitialized. Its value is the characters of the symbol itself, translated to uppercase (that is, lowercase a-z to uppercase A-Z). However, if it is a compound symbol (described under Compound Symbols), its value is the derived name of the symbol.

Example:

/* If Freda has not yet been assigned a value,   */
/* then next line gives FRED the value "FREDA"   */
Fred=Freda

The meaning of a symbol in Rexx varies according to its context. As a term in an expression, a symbol belongs to one of the following groups: constant symbols, simple symbols, compound symbols, environment symbols, and stems. Constant symbols cannot be assigned new values. You can use simple symbols for variables where the name corresponds to a single value. You can use compound symbols and stems for more complex collections of variables although the collection classes might be preferable in many cases. See The Collection Classes.

Extended Assignments

The character sequences +=, -=, *= /=, %=, //=, ||=, &=, |=, and &&= can be used to create extended assignment instructions. An extended assignment combines a non-prefix operator with an assignment where the term on the left side of the assignment is also used as the left term of the operator. For example,

    a += 1

is exactly equivalent to the instruction

    a = a + 1

Extended assignments are processed identically to the longer form of the instruction.

Constant Symbols

A constant symbol starts with a digit (0-9) or a period.

You cannot change the value of a constant symbol. It is simply the string consisting of the characters of the symbol (that is, with any lowercase alphabetic characters translated to uppercase).

These are constant symbols:

77
827.53
.12345
12e5       /* Same as 12E5 */
3D
17E-3

Symbols where the first character is a period and the second character is alphabetic are environment symbols. Environment symbols). may have a value other other than the symbol name.

Simple Symbols

A simple symbol does not contain any periods and does not start with a digit (0-9).

By default, its value is the characters of the symbol (that is, translated to uppercase). If the symbol has been assigned a value, it names a variable and its value is the value of that variable.

These are simple symbols:

FRED
Whatagoodidea?    /* Same as WHATAGOODIDEA? */
?12

Stems

A stem is a symbol that contains a single period as the last character of the name. It cannot start with a digit.

These are stems:

FRED.
A.

The value of a stem is always a Stem object. (See The Stem Class.) The stem variable's Stem object is automatically created the first time you use the stem variable or a compound variable) containing the stem variable name. The Stem object's assigned name is the name of the stem variable (with the characters translated to uppercase). If the stem variable has been assigned a value, or the Stem object has been given a default value, the assigned name override the default stem name. A reference to a stem variable will return the associate Stem object.

When a stem is the target of an assignment, the action taken depends on the value being assigned. If the new value is a Stem object, the new Stem object will replace the the Stem object that is currently associated with the stem variable. This can result in multiple stem variables referring to a the same Stem object, effectively creating a variable alias.

Example:

hole.   = "empty"
hole.19 = "full"
say  hole.1  hole.mouse  hole.19
/* Says "empty empty full" */

hole2. = hole.       /* copies reference to hole. stem to hole2. */

say  hole2.1  hole2.mouse  hole2.19

/* Also says "empty empty full" */

If the new value is not a Stem object, a new Stem object is created and assigned to the stem variable, replacing the Stem object currently associated with the stem variable.

The new value assigned to the stem variable is given to the new Stem object as a default value. Following the assignment, a reference to any compound symbol with that stem variable returns the new value until another value is assigned to the stem, the Stem object, or the individual compound variable.

Example:

hole.  = "empty"
hole.19 = "full"
say  hole.1  hole.mouse  hole.19
/* says "empty empty full" */

Thus, you can initialize an entire collection of compound variables to the same value.

You can pass stem collections as function, subroutine, or method arguments.

Example:

/* CALL RANDOMIZE count, stem. calls routine */
Randomize: Use Arg count, stem.
do i = 1 to count
  stem.i = random(1,100)
end
return

The USE ARG instruction functions as an assignment instruction. The variable STEM. in the example above is functionally equivalent to:

stem. = arg(2)

Note: USE ARG must be used to access the stem variable as a collection. PARSE and PARSE ARG will force the stem to be a string value.

Stems can also be returned as function, subroutine, or method results. The resulting return value is the Stem object associated with the stem variable.

Example:

/* RANDOMIZE(count) calls routine */
Randomize: Use Arg count
do i = 1 to count
  stem.i = random(1,100)
end
return stem.

When a stem. variable is used in an expression context, the stem variable reference returns the associated Stem object. The Stem object will forward many object messages to it's default value. For example, the STRING method will return the Stem object's default value's string representation:

total. = 0
say total.                         /* says "0" */

The [] method with no arguments will return the currently associated default value. variables can always be obtained by using the stem. However, this is not the same as using a compound variable whose derived name is the null string.

total. = 0
null = ""
total.null = total.null + 5
say total.[] total.null              /* says "0 5" */

You can use the DROP, EXPOSE, and PROCEDURE instructions to manipulate collections of variables, referred to by their stems. DROP FRED. assigns a new Stem object to the specified stem. (See DROP.) EXPOSE FRED. and PROCEDURE EXPOSE FRED. expose all possible variables with that stem (see EXPOSE and PROCEDURE).

The DO instruction can also iterate over all of the values assigned to a stem variable. See DO for more details.

Notes:

  1. When the ARG, PARSE, PULL, or USE instruction, the VALUE built-in function, or the variable pool interface changes a variable, the effect is identical with an assignment.

  2. Any clause that starts with a symbol and whose second token is (or starts with) an equal sign (=) is an assignment, rather than an expression (or a keyword instruction). This is not a restriction, because you can ensure that the clause is processed as a command, such as by putting a null string before the first name, or by enclosing the expression in parentheses.

    If you unintentionally use a Rexx keyword as the variable name in an assignment, this should not cause confusion. For example, the following clause is an assignment, not an ADDRESS instruction:

    Address="10 Downing Street";
  3. You can use the VAR function (see VAR) to test whether a symbol has been assigned a value. In addition, you can set SIGNAL ON NOVALUE to trap the use of any uninitialized variables (except when they are tails in compound variables or stem variables, which are always initialized with a Stem object when first used.

Compound Symbols

A compound symbol contains at least one period and two other characters. It cannot start with a digit or a period, and if there is only one period it cannot be the last character.

The name begins with a stem (that part of the symbol up to and including the first period) and is followed by a tail, which are parts of the name (delimited by periods) that are constant symbols, simple symbols, or null. Note that you cannot use constant symbols with embedded signs (for example, 12.3E+5) after a stem; in this case the whole symbol would not be valid.

These are compound symbols:

FRED.3
Array.I.J
AMESSY..One.2.

Before the symbol is used, that is, at the time of reference, the language processor substitutes in the compound symbol the character string values of any simple symbols in the tail (I, J, and One in the examples), thus generating a new, derived tail. The value of a compound symbol is, by default, its the name of the Stem object associated with the stem variable concatenated to the derived tail or, if it has been used as the target of an assignment, the value of Stem element named by the derived tail.

The substitution in the symbol permits arbitrary indexing (subscripting) of collections of variables that have a common stem. Note that the values substituted can contain any characters (including periods and blanks). Substitution is done only once.

More formally, the derived name of a compound variable that is referenced by the symbol

s0.s1.s2. --- .sn

is given by

d0.v1.v2. --- .vn

where d0 is the name of the Stem object associated with the stem variable s0 and v1 to vn are the values of the constant or simple symbols s1 through sn. Any of the symbols s1 to sn can be null. The values v1 to vn can also be null and can contain any characters (including periods). Lowercase characters are not translated to uppercase, blanks are not removed, and periods have no special significance. There is no limit on the length of the evaluated name.

Some examples of simple and compound symbols follow in the form of a small extract from a Rexx program:

a=3       /* assigns "3" to the variable A    */
z=4                 /*   "4"      to Z        */
c="Fred"            /*   "Fred"   to C        */
a.z="Fred"          /*   "Fred"   to A.4      */
a.fred=5            /*   "5"      to A.FRED   */
a.c="Bill"          /*   "Bill"   to A.Fred   */
c.c=a.fred          /*   "5"      to C.Fred   */
y.a.z="Annie"       /*   "Annie"  to Y.3.4    */
say  a  z  c  a.a  a.z  a.c  c.a  a.fred y.a.4
/* displays the string:                     */
/*    "3 4 Fred A.3 Fred Bill C.3 5 Annie"  */

You can use compound symbols to set up arrays and lists of variables in which the subscript is not necessarily numeric, thus offering a great scope for the creative programmer. A useful application is to set up an array in which the subscripts are taken from the value of one or more variables, producing a form of associative memory (content-addressable).

Evaluated Compound Variables

The value of a stem variable is always a Stem object (see The Stem Class for details). A Stem object is a type of collection that supports the [] and []= methods used by other collection classes. The [] method provides an alternate means of accessing compound variables that also allows embedded subexpressions.

Examples:

a=3       /* assigns "3" to the variable A    */
z=4                 /*   "4"      to Z        */
c="Fred"            /*   "Fred"   to C        */
a.[z]="Fred"        /*   "Fred"   to A.4      */
a.[z+1]="Rick"      /*   "Rick"   to A.5      */
a.[fred]=5          /*   "5"      to A.FRED   */
a.[c]="Bill"        /*   "Bill"   to A.Fred   */
c.[c]=a.fred        /*   "5"      to C.Fred   */
y.[a,z]="Annie"     /*   "Annie"  to Y.3.4    */
say  a  z  c  a.[a] a.[z]  a.[z+1]
a.[c]  c.[a]  a.[fred] y.[a,z]
/* displays the string:                     */
/*    "3 4 Fred A.3 Fred Rick Bill C.3 5 Annie"  */

Environment Symbols

An environment symbol starts with a period and has at least one other character. This character must not be a digit. By default the value of an environment symbol is the string consisting of the characters of the symbol (translated to uppercase). If the symbol identifies an object in the current environment, its value is the mapped object.

These are environment symbols:

.method    // A reference to the Rexx Method class

.true      // The Rexx "true" object.  Has the value "1"

.xyz       // Normally the value .XYZ

When you use an environment symbol, the language processor performs a series of searches to see if the environment symbol has an assigned value. The search locations and their ordering are:

  1. The directory of classes declared on ::CLASS directives (see ::CLASS) within the current program package or added to the current package using the addClass() method.

  2. The directory of PUBLIC classes declared on ::CLASS directives of other files included with a ::REQUIRES directive or added to the current Package instance using the addPackage() method.

  3. The local environment directory specific to the current interpreter instance. The local environment includes process-specific objects such as the .INPUT and .OUTPUT objects. You can directly access the local environment directory by using the .LOCAL environment symbol. (See The Local Environment Object (.LOCAL).)

  4. The global environment directory. The global environment includes all permanent Rexx objects such as the Rexx supplied classes (.ARRAY and so on) and constants such as .TRUE and .FALSE. You can directly access the global environment by using the .ENVIRONMENT environment symbol (see The Environment Object). Entries in the global environment directory can also be accessed via the VALUE built-in function (see VALUE) by using a null string for the selector argument.

  5. Rexx defined symbols. Other simple environment symbols are reserved for use by Rexx built-in environment objects. The currently defined built-in objects are .RS, .LINE, .METHODS, .ROUTINES, and .CONTEXT.

If an entry is not found for an environment symbol, then the default character string value is used.

Note: You can place entries in both the .LOCAL and the .ENVIRONMENT directories for programs to use. To avoid conflicts with future Rexx defined entries, it is recommended that the entries that you place in either directory include at least one period in the entry name.

Example:

/* establish settings directory */
.local~setentry("MyProgram.settings", .directory~new)