roo!™
Language Specification

Hop into the future !

This document describes roo!™ programming language capabilities.

Observe: square brackets are used in two ways within this document. Generally, these indicate that the enclosed syntactic elements are optional. Alternatively, square brackets can be specified within expression syntax. These latter brackets are shown larger than the associated text, and in dark red. You will be able to easily recognize these larger square brackets. The normal size square brackets always enclose optional syntactic elements.


1 roo!™ language objectives


2 Rexx programs are roo!™ programs !

roo!™ is an object-oriented enhancement of r4™, which is Kilowatt Software L.L.C.'s Classic Rexx language offering. All Rexx capabilities that are supported by r4™ are supported by roo!™. roo!™ supports all Classic Rexx instructions and built-in functions, as well as the invocation of Classic Rexx internal and external procedures as subroutines and functions.

roo!™ programs can differ from Classic Rexx programs by the use of a handful of object-oriented capabilities that are described below. An assortment of built-in classes are provided as well.


3 Program source files

roo!™ supports two types of source files.

  1. Program source files

  2. Class definition files

3.1 Program source file

A program source file consists of:

A program can optionally use roo!™'s language extensions. The csv2xml example program uses various roo!™'s language extensions, to convert a comma-separated value (CSV) file to an equivalent eXtended Markup Language (XML) file.

When additional roo!™ capabilities are not used the program can be interpreted by r4™ directly. In addition, if the program does not use any r4™ extensions, then the program should be executable by other Classic Rexx interpreters. The calc example program does not use any r4™ or roo!™ extensions.

Note: r4™ extensions are described in the separate R4.HTM document.


3.2 roo!™ object-oriented programming

Although roo!™ can interpret Classic Rexx programs, it can also do much more. With roo!™ you can develop object-oriented programs.


3.2.1 A class file "defines" a programming object

A roo!™ class definition is a source file that defines a new programming object. An object can encapsulate a collection of data values, that are accessible exclusively by the object's methods. In addition, an object can be defined by a hierarchy of classes. The bottommost class in the hierarchy is called the base class. The other classes in the hierarchy are derivations of base class capabilities. Each class can share variables with other classes in the class hierarchy. Derived classes can also override the methods of a base class. The base class can provide the fundamental behavior of a method, and a derived class can refine this behavior. Overriding a method is called polymorphism in object-oriented programming parlance. The base class can be either a class that you define, or it can be a roo!™ built-in class.


3.2.2 roo!™ class definition file

A roo!™ class definition file consists of:

The msgbox example is a roo!™ class definition file that exhibits various object-oriented capabilities.


3.2.3 Class definition instruction

This instruction defines the characteristics of class className. A class instruction is optional within a class source file. When the class instruction is absent, the class is a simple roo!™ class.

When present, the class instruction must be the first instruction in its source file. Only one class definition is permitted per class source file. The className label is recommended, although optional, on the class instruction. The class is instantiated by its source file name. To help other programmers, or yourself, the className label should correspond to the source file name. For example:

The file name portion of the class source file name, in upper case, symbolically references the class. For example, if the source file name is "c:\roo\secondBase.roo", the symbolic class name will be secondbase. A request for another class file that has the same symbolic class name will use the prior class definition, even if it is in another directory, or has a different extension. Thus, "c:\somewhereElse\secondBase.xyz" will use the class definition in "c:\roo\SECONDbase.roo" if it was previously activated. This is because the symbolic class names for both of these files match.

Suggestion: when you prepare a new class source file always check to see if another file with the same symbolic class name exists. Be aware the other file may be located in the directories associated with the ROOPATH environment variable.

When the extends phrase is specified the current class is a derivative of baseClass. The baseClass is located by a program search, with an implicit default class extension unless an explicit extension is specified within the baseClass term. The baseClass can also be an explicit file system name; such as, "c:\roo\first base.roo".

Normally, the base class is constructed before the current class is initialized. When the explicitly keyword is specified, the initialize method of the current class is activated before the base class is constructed. The base class is constructed explicitly when the following instruction is performed in the initialize method.

When the base class is not explicitly constructed, the same arguments are passed to the initialization methods of the base class, and then the deriving class, in the same sequence. When the base class is explicitly constructed the arguments that are passed to the base class initialization method can be dynamically prepared, or rearranged, by the deriving class.

None of the base class methods should be used until the base class is initialized. If an initialize method in a deriving class does not explicitly initialize the base class, then the base class is implicitly initialized when the initialize method of the deriving class concludes.

Observe: as mentioned earlier, class definitions are reused until all class instances conclude. Changes to the associated source file will not be effective while class instances are active. Often, it will be necessary to halt the roo!™ environment in order for class source file revisions to become effective.


3.2.4 Class variables

There are three types of roo!™ class variables. These are defined within local, shared, and static instructions. The value of a class variable persists from one method invocation to the next. If you have used other object-oriented programming languages you might refer to these as member variables, which might have various access specifiers; such as: public, private, protected, etc.

Note: unlike other programming languages, roo!™ class variables are never publicly accessible. This assures that the value of a class variable is always encapsulated.

3.2.4.1 Local class variable instruction

The local instruction identifies one or more variables that are locally persistent for the methods within the current class source file. A separate collection of local variables is established for each class instance. The variableName values are either simple variable names, or compound stem variable names. Simple variable names do not contain a period. Compound stem variable names contain one period, which is the last character in the name.

Multiple local instructions are permitted within a class source file. Often a single local instruction is present at the beginning of the file. However, a local instruction can be placed anywhere within the file. Local variables can be declared adjacent to the point of use. It is not an error to declare the same variable as a local variable multiple times.

3.2.4.2 Shared class variable instruction

The shared instruction identifies one or more variables that are persistently shareable by the methods of all classes within a class hierarchy. A separate collection of shared variables is established for each class instance. The variableName values are either simple variable names, or compound stem variable names. Simple variable names do not contain a period. Compound stem variable names contain one period, which is the last character in the name. A class that is a refinement of another class must declare the variables that it is sharing; otherwise, confounding problems would arise. For example, what had been a temporary variable, in a method of a derived class, could accidentally become a shared variable as a result of a subsequent addition of the variable to the list of shared variables within the base class.

Multiple shared instructions are permitted within a class source file. Often a single shared instruction is present at the beginning of the file. However, a shared instruction can be placed anywhere within the file. Shared variables can be declared adjacent to the point of use. It is not an error to declare the same variable as a shared variable multiple times.

3.2.4.3 Static class variable instruction

The static instruction identifies one or more variables that are shared by all instances of a class definition. Static variables have class scope, instead of instance scope. The variableName values are either simple variable names, or compound stem variable names. Simple variable names do not contain a period. Compound stem variable names contain one period, which is the last character in the name.

Multiple static instructions are permitted within a class source file. Often a single static instruction is present at the beginning of the file. However, a static instruction can be placed anywhere within the file. Static variables can be declared adjacent to the point of use. It is not an error to declare the same variable as a static variable multiple times.

Static variables can be initialized by a preinitialize method. A corresponding finalize method allows resources that are stored in static variables to be properly terminated.

3.2.4.4 Class variable usage errors

Note: it is erroneous to declare a variable in more than one class variable group. For example, it is incorrect for a variable to be declared both shared and local, or shared and static. When a conflicting variable definition is encountered the following syntax error condition is raised.

Note: when a local, shared, or static variable name is a compound symbol name the following syntax error condition is raised.


3.2.5 Method definition

A method definition is similar to a Classic Rexx internal procedure, without a variable exposure phrase. As indicated, the method instruction is optional, although recommended. When present, it is annotative, and helpful for program readers. All labels within the class source file are eligible for method invocation. These are also eligible targets for signal instructions. As in Classic Rexx programs, an unexpected method instruction is an error (code #17 -- unexpected procedure or method).

Observe: when the method instruction is absent, it is possible for program execution to flow into the method. This may introduce a logic flaw. Generally, you should use the method keyword, to avoid unexpected control flow transitions.

Unlike Classic Rexx internal procedures, methods are not invoked by the call instruction or by function calls. Methods are accessed by new invocation techniques. Methods can be invoked by either a prefix operator, or an infix operator.


4 Class instance creation request

The ^^ prefix operator creates an instance of the class that is defined in classFileName. The classFileName is located by a program search, with an implicit default class extension unless an explicit extension is specified within the classFileName term. The classFileName can also be an explicit, quoted file system name; such as, "c:\roo\first base.roo".

When the parenthesized argument list is omitted, and classFileName is unquoted, the class file name is the value of the variable named classFileName. The example program named qt.rooProgram creates a class which is the value of variable outputEmitter.

During instance creation the initialize method of the class is implicitly invoked. The optional arguments within the parentheses are passed as parameters to the initialize method. If the initialize method returns the empty string, the instance is created. Any other result from the initialize method is considered an error, and consequently the class instance is not created.

The resulting classInstanceReference is set to an error message if an error occurs during instance creation. Otherwise the classInstanceReference can be used to invoke various class methods.

The classInstanceReference can be assigned to multiple Rexx variables -- via assignment (=), arg, parse, and pull instructions. The classInstanceReference can also be passed as a parameter during a method invocation, or in a subroutine or function call. In turn, the parameter value can be assigned to variables in the target method, subroutine, or function. Each time the classInstanceReference is assigned to a Rexx variable, the number of uses of the class instance is incremented. When each of these variables is deactivated (via a drop instruction or method/procedure termination) the number of uses of the class instance is decremented. When the number of class instance uses is zero the class instance is discarded. The terminate method is implicitly invoked during class instance removal.


Note: there is no corollary to the ^^ operator -- i.e. a destroy operator. A class instance is only removed when the number of active instance uses reaches zero.

The ^^ operator is pronounced as the double-hop operator. The ^^ operator has the same precedence as other Rexx prefix operators.


4.1 Using a new instance directly in an expression

It is possible to use the resulting classInstanceReference directly in a Rexx expression wherever a term is expected, without assigning it to a variable. In this case, the number of class instance uses is temporarily incremented during the evaluation of the current instruction, and then decremented when the instruction completes.

Here are several examples that show how a classInstanceReference can be used directly in a Rexx expression.

The resulting classInstanceReference can be used in place:

Using a classInstanceReference directly in a Rexx expression is EXPOSED to potential syntax errors, if the class instance is not properly initialized. The syntax error can be avoided by enabling a signalled OBJECTION condition handler as shown in the example.


4.2 Initialization error message format

When the resulting classInstanceReference is set to an error message it is formatted as follows:

classFileName is the name of the class that was initialized.

initializationMethodReturnValue is the text that is returned by the initialize method.


5 Method invocation syntax

Methods are invoked with either a prefix ^ operator, or an infix ~ operator. A prefix ^ operator can be used to invoke methods within the current class context. These methods can be in the current class, a base class, or a derived class. An infix ~ operator is used to invoke instances in other class contexts. An infix ~ operator is preceded by an instance reference.

Note: the caret and tilde characters are unused in Classic Rexx.

Hint: to help you distinguish between the ^ and ~ operators, the ^ and ^^ are both prefix operators, whereas a ~ is an infix operator. You learned about the ^^ prefix operator in the class instance creation section above.

The tilde operator is not a true Rexx operator. Like other Rexx operators, spaces before and after the tilde are discarded, in the normal way. Yet, the tilde binds strongly to its left and right elements, producing a Rexx term. The classInstanceReference on the left side of the tilde can be determined as the value of an expression.

The following example shows how the tilde operator binds to its adjacent elements. The value of v ~ size is treated as a term.

Observe: prefix operators have a higher precedence than the tilde operator. Consequently, you will have to enclose the method invocation in parentheses to avoid having the method name processed by a prefix operator. Here is an example of an invalid invocation expression.

Here is the corrected version:

Hint: built-in aggregate classes, such as the stack class, also have an isNonEmpty method. This method is preferred for use in loops, because it avoids the difficulty associated with the not (\) prefix operator. Here is the code again, which uses the isNonEmpty method.

The classInstanceReference is a value that was returned from a class instance creation request.

The classInstanceReference can also be one of the following:

Observe: that the words self and base are enclosed in quotes above, because self and base are not reserved keywords. If these are unquoted, they are simple symbols. Unusual surprises could be in store if these symbols are assigned values!

The single caret operator has the same precedence as other Classic Rexx prefix operators -- i.e. the highest order of precedence. A prefix ^ operator is used to invoke methods in the current class, or a base class.

All methods are invoked as functions, and thus must return a result. If a result is not returned the following syntax error condition is raised: Error 44, Function (or method) did not return data.

A method in a derived class overrides a method with the same name in a base class. The base class provides a default implementation of the method. Note: the method in the derived class can explicitly invoke the base class method during processing, as follows:

The ^ operator is pronounced as the hop operator.

5.1 Another invocation circumstance -- treating a Rexx value as a String object instance

It is possible that the classInstanceReference in a method invocation could actually be a normal Rexx value instead. Rather than treating this situation as a syntax error, the expression is converted to a function call instead. For example:

is transformed to:

This allows the result of a method invocation to be passed to a built-in function, without embedding it within the first function parameter. Here is an example:

This invocation technique can also be used to invoke internal and external procedures as functions. Again, the value on the left side of the tilde becomes the first argument to the procedure.


6 Class preinitialization method

When a class is initially loaded the optional preinitialize method of the class is implicitly invoked. This method can initialize static variables. This method is invoked as a subroutine (as though CALLed), without any arguments. The preinitialize method can call other procedures within the class file as subroutines or functions. The preinitialize method does NOT have an instance context, so it cannot invoke other methods with the single caret operator (^). Also, the absence of an instance context, makes references to local, or shared variables improper. These will be resolved as normal Rexx procedure variables instead.

The preinitialize method can establish new instances with the double caret operator (^^). The returned instance values can be assigned to static variables. If returned instance values are assigned to local variables, these will be removed when the associated execution context concludes.

The preinitialize method must return a result. If the result is the empty string class creation is considered successful. Otherwise, an error string should be returned to indicate class pre-initialization was unsuccessful. The error string will be displayed to the console.


7 Class finalization method

When a class is removed the optional finalize method of the class is implicitly invoked, so that resources stored in static variables can be properly terminated. The finalize method can reference static variables. This method is invoked as a subroutine (as though CALLed), without any arguments. The finalize method can call other procedures within the class file as subroutines or functions. The finalize method does NOT have an instance context, so it cannot invoke other methods with the single caret operator (^). Also, the absence of an instance context, makes references to local, or shared variables improper. These will be resolved as normal Rexx procedure variables instead.

The finalize method can establish new instances with the double caret operator (^^). The returned instance values can be assigned to static variables.

The finalize method can return a result. This result is ignored.

Note: the finalize method is invoked when a class is being removed, not when a class instance is removed.


8 Class initialization method

Each class has an optional initialize method.

This method is particularly important for classes that are associated with named resources -- such as: disks, directories, streams, etc. If access to these resources is unsuccessful, the initialize method can return informative error text, and the instance will no longer be active.

When a class instance is created the initialize method of the class is implicitly invoked. This can process optional arguments that are passed from the instance creation request. The initialize method must return a result. If the result is the empty string instance creation is considered successful. Otherwise, an error string should be returned to indicate that class instance creation was unsuccessful, and an OBJECTION condition will be raised if it is enabled. The error string will be provided as the condition's description text. If the OBJECTION condition is not enabled, the error text is returned as part of the instance creation result error text.

Successful initialization of an instance can be determined by using the 'Instance' type of the datatype built-in function. An example is presented there, which shows how an incorrectly initialized class instance can be handled.


9 Class self method

Occasionally it is helpful to return a reference to the current class instance at the conclusion of a method. This allows the calling context to invoke other instance methods subsequently within the same instruction. Various built-in class methods return a reference to the current class instance. Within methods that you develop it is very easy to return a reference to the current class instance. Here is how:

This permits the invocation context to be programmed as follows:

If the special self method were unavailable, the invocation context would require multiple instructions, as follows:


10 Class termination method

When the number of uses of a class instance reaches zero the terminate method of the class is implicitly invoked. No arguments are available for the terminate method. The terminate method can reference and alter local, shared, and static class variables. The terminate method can create new class instances as well. The terminate method is optional.

Note: the terminate method is invoked when a class instance is removed.


11 Roo extensions to the Rexx language

This section describes extensions to the underlying Rexx language.

11.1 Additional reserved keyword instructions

The following reserved keyword instructions were added:

11.2 New expression operators

There are four new expression operators:

11.3 OBJECTION condition

The OBJECTION error condition was added. This condition is raised, if enabled, when the INITIALIZE method of a class returns an error string. The INITIALIZE method's error string is provided in the information that is returned by the condition built-in function's description string. The description string also includes information about the class that was accessed.

The OBJECTION error condition is processed analogously to the NOTREADY error condition. The condition is initially disabled. It can be enabled by using either the CALL ON or SIGNAL ON instructions. An example of its use is provided below.

The following is the syntax of the instructions that enable and disable OBJECTION conditions.

The following example shows how errors during class instance initialization can be bypassed by using a signal on OBJECTION instruction.

11.4 Datatype built-in function -- Instance data type

The datatype built-in function has a minor, but important, addition -- the Instance data type. This is used to conditionally perform instructions, only if the associated object instance was properly created.

An additional Instance type is supported for the datatype built-in function. This returns 1 if the possibleInstanceValue argument is a class instance, and 0 otherwise.

The following shows how to assure that an instance of class abc was properly initialized.

11.5 Revision of command instruction recognition

The usual Rexx technique for distinguishing commands from other instructions is generally in effect. However, when a potential command instruction contains special roo!™ operator characters the instruction is considered as a roo!™ object instruction instead. The special roo!™ operator characters are unquoted: square brackets ([ ]), caret (^), or tilde (~) characters. Thus, the following is not a command:

To perform the result of a method as a command, the instruction must begin with an unquoted exclamation point (!). Thus the following is performed as a command:

You can precede command lines, that do not contain special roo!™ operator characters, with an exclamation point as well. The leading exclamation point is discarded from the text before the command is performed.

Hint: if you need to start a command, that does not contain special operator characters, with an exclamation point then enclose it within quotes.

11.6 Shorthand vector expressions

A commonly used built-in class is a vector of items. A vector class instance is prepared by normal class construction and initialization. The following is an example:

roo!™ supports a shorter alternative that uses curly braces, as follows:

Methods can be applied after the right curly brace, as follows:

Vectors can be nested as follows:

A vector of vectors can be composed as follows:

An empty vector can be prepared as follows:

Hint: your use of curly braces is optional. When displayed with a small font, curly braces can be difficult to distinguish from parentheses. When defining a vector, that will receive items subsequently, you may prefer to use the long hand form instead, as follows:

Note: the curly braces are transformed to the alternative long hand vector notation during the initial scanning phase of a roo!™ source file. Consequently, the long hand format will appear in trace source display output. The original source text, with the braces, will appear in the result of a sourceline built-in function request.

11.7 Interactive trace context request

In an object-oriented environment it can be difficult to determine the calling context associated with an interactive trace prompt. You can request the calling context by entering the word context at an interactive trace prompt:

Note: #nnn ? is the text of the interactive trace prompt, which shows the current source line number (nnn).

The current procedure and method calling contexts are listed. The information that is displayed uses the ContextVector built-in class. Please refer to the description of the ContextVector built-in class to interpret the information that is displayed.

11.8 Additional built-in functions

Several built-in functions were added.

Observe: more built-in functions were added for NetRexx compatibility. These are described in another section below.

11.8.1 Callback built-in function -- roo!™ DLL execution mode only

A callback function was added. This function is only supported when roo!™ is operating in DLL execution mode. The syntax of the callback function is:

This function transfers control to a callback routine in the context that invoked the roo!™ DLL's 'PerformWithCallback', 'CreateClassWithCallback', or 'InvokeMethodWithCallback' entry.

Hint: a callback allows the roo!™ program to send information back to the calling context. In addition, the calling context can return information to the roo!™ program, via the result.

Click here to review the testRooDll.cpp example program that uses the DLL entry points described above.

11.8.2 Nap built-in function

A nap function was added. This function enables a program to pause temporarily. The syntax is:

numberOfMilliseconds is a non-negative number of milliseconds to nap.

The result is a time value, which is the number of milliseconds since system startup.

11.8.3 RaiseObjection built-in function

A RaiseObjection function was added. This enables a program to dynamically raise an OBJECTION condition, often to the calling procedure or method scope.

The RaiseObjection function is typically CALLed. The syntax is:

The RaiseObjection function returns "1" always.

conditionErrorText is a general description of the OBJECTION condition.

additionalInformation provides optional, detailed information regarding the OBJECTION condition.

Observe: if the OBJECTION condition is enabled in the current procedure or method execution scope, it is handled locally. If the OBJECTION condition is not enabled in the current procedure or method execution scope, the current scope is concluded and the OBJECTION is passed to the higher execution scope, if it is handled in the higher scope. If the OBJECTION condition is not handled at all, it is treated as a SYNTAX condition in the current execution scope.

Note: the NetRexx language uses the signal instruction to raise objections in a similar manner. roo!™ provides an implementation of the signal instruction which is compatible with Classic Rexx usages, consequently it could not be used for condition raising.

11.8.4 Split built-in function

The split function partitions a string into a vector of segments. The syntax is:

separator must not be an empty string.

The result is a vector, which contains the segments of string that are divided by separator.

The following is an example of usage of the split function.

The separator can contain more than one letter. For example:

Hint: join is an alias of the toDelimitedString method in the vector built-in class.

Observe:The split function is equivalent to:

Note: the split function emulates the function with the same name in JavaScript, and Perl. Similarly, the join method in the vector built-in class emulates the converse functionality that is used in these other languages. The join method prepares a delimited string from a vector of strings.

11.8.5 Square root built-in function

A squareroot function was added. The syntax is:

number must be non-negative.


11.9 NetRexx extensions

roo!™ provides the following capabilities which were innovations of the NetRexx programming language.