By analyzing your problem in terms of objects, you can determine what classes need to be created. You can create a class using messages or directives. Directives are a new kind of Rexx clause, and they are preferred over messages because the code is easier to read and understand, especially in large programs. They also provide an easy way for you to save your class definitions and share them with others using the PUBLIC option.
A Rexx program is made up of one or more executable units. Directives separate these units, which themselves are Rexx programs. Rexx processes all directives first to set up any classes, methods, or routines needed by the program. Then it runs any code that exists before the first directive. The first directive in a program marks the end of the executable part of the program. A directive is a kind of clause that begins with a double-colon (::) and is non-executable (a directive cannot appear in the expression of an INTERPRET instruction, for example).
The following is a short summary of all the Rexx directives. See the Open Object Rexx: Reference for more details on, or examples of, any of these Rexx directives.
You use the ::CLASS directive to create a class. Programs can then use the new class by specifying it as a Rexx environment symbol (the class name preceded by a period) in the program. For example, in A Sample Program Using Directives, the Savings class is created using the ::CLASS directive. A program can then use the new class by specifying it as an environment symbol, ".savings".
The new class that you create acquires any methods defined by subsequent ::METHOD directives within the program, until either another ::CLASS directive or the end of the program is reached.
You can use the ::CLASS directive's SUBCLASS option to make the new class the subclass of another. In A Sample Program Using Directives, the Savings class is made a subclass of the Account class. A subclass inherits instance and class methods from its specified superclass; in the sample, Savings inherits from Account.
Additional ::CLASS directive options are available for:
Inheriting instance methods from a specified metaclass as class methods of the new class (the METACLASS option). For more information on metaclasses, see Metaclasses.
Making the new class available to programs outside its containing Rexx program (the PUBLIC option). The outside program must refer to the new class by using a ::REQUIRES directive.
Subclassing the new class to a mixin class in order to inherit its instance and class methods (the MIXINCLASS option).
Adding the instance and class methods of a mixin class to the new class, without subclassing it (the INHERIT option).
When you create a new class, it is always a subclass of an existing class. If you do not specify the SUBCLASS or MIXINCLASS option on the ::CLASS directive, the superclass for the new class is the Object class.
Your class definition can be in a file of its own, with no executable code preceding it. For example, when you define classes and methods to be shared by several programs, you put the executable code in another file and refer to the class file using a ::REQUIRES directive.
Rexx processes ::CLASS directives in the order in which they appear, unless there is a dependency on some later directive's processing. You cannot create two classes that have the same class name in one program. If several programs contain classes with the same name, the last ::CLASS directive processed is used.
The ::CLASS directive is usually followed by a ::METHOD directive, which is used to create a method for that class and define the method's attributes. The next directive in the program, or the end of the program, ends the method.
Some classes you define have an INIT method. INIT is called whenever a NEW message is sent to a class. The INIT method must contain whatever code is needed to initialize the object.
It is not required that a ::METHOD directive be preceded by a ::CLASS directive. However, without it the method is only accessible by the executable part of the program through Rexx's .METHODS environment symbol. This symbol identifies a directory of methods that you can refer to by name. For each method name only one method directive can appear that is not associated with a class.
The ::METHOD directive can be used for:
Creating a class method for the most-recent ::CLASS directive (the CLASS option).
Creating a private method; that is, a method that works like a subroutine and can only be activated by the object it belongs to--otherwise the method is public by default, and any sender can activate it.
Creating a method that can be called while other methods are active on the same object, as described in Activating Methods (the UNGUARDED option).
Creating the instance methods method_name and method_name= for the preceding ::CLASS directive (the ATTRIBUTE option).
You use the ::ROUTINE directive to create a named routine within a program. The ::ROUTINE directive starts the named routine and another directive (or the end of the program) ends the routine.
The ::ROUTINE directive is useful for defining lower-level routines that are called by several methods. These methods might be in unrelated classes or in different applications. You use ::ROUTINE when you have a utility that you do not want to appear as a method.
The ::ROUTINE directive includes a PUBLIC option for making the routine available to programs outside its containing Rexx program. The outside program must reference the routine by using a ::REQUIRES directive.
Only one ::ROUTINE directive can appear for a routine name within a program.
You use the ::REQUIRES directive when a program needs access to the classes and objects of another program. This directive has the following form:
::REQUIRES program_name
The ::REQUIRES directive must precede all other directives, and the order of the ::REQUIRES directives determines the search order for the classes and routines defined in the named programs.
Local routine or class definitions within a program override routines or classes of the same name in programs that are accessed through ::REQUIRES directives. Another directive (or the end of the program) must follow a ::REQUIRES directive.
You place a directive (and its method code) after the program code. When you run a program containing directives, Rexx:
Processes the directives first, to set up the program's classes, methods, and routines.
Runs any program code preceding the first directive. This code can use any classes, methods, and routines set up by the directives.
Once Rexx has processed the code preceding the directive, any public classes and objects the program defines are available to programs having the appropriate ::REQUIRES directive.
Here is a program that uses directives to create new classes and methods:
asav = .savings~new /* executable code begins */ say asav~type /* executable code */ asav~name= "John Smith" /* executable code ends */ ::class Account /* directives begin ... */ ::method "TYPE" return "an account" ::method "NAME=" expose name use arg name ::class Savings subclass Account ::method "TYPE" return "a savings account" /* ... directives end */
The preceding program uses the ::CLASS directive to create two classes, the Account class and its Savings subclass. In the ::class Account expression, the ::CLASS directive precedes the name of the new class, Account.
The example program also uses the ::METHOD directive to create TYPE and NAME= methods for Account. In the ::method "TYPE" expression, the ::METHOD directive precedes the method name, and is immediately followed by the code for the method. Methods for any new class follow its ::CLASS directive in the program, and precede the next ::CLASS directive.
In the ::method "NAME=" method, the USE ARG instruction retrieves the argument. The EXPOSE instruction, which must immediately follow the ::METHOD directive, makes the value (here, "John Smith") available for use by other methods. A variable in an EXPOSE instruction is called an object variable.
You do not have to associate object variables with a specific object. Rexx keeps track of object variables for you. Whenever you send a message to savings account Asav, which points to the Name object, Rexx knows what internal object value to use. If you assign another value to Asav (such as "Mary Smith"), Rexx deletes the object that was associated with Asav ("John Smith") as part of its normal garbage-collection operations.
In the Savings subclass, a second TYPE method is created that supersedes the TYPE method Savings would otherwise have inherited from Account. Note that the directives appear after the program code.
A directive is nonexecutable code that begins with a double colon (::) and follows the program code. The ::CLASS directive creates a class; in this example, the Dinosaur class. The sample provides two methods for the Dinosaur class, INIT and DIET. These are added to the Dinosaur class using the ::METHOD directives. After the line containing the ::METHOD directive, the code for the method is specified. Methods are ended either by the start of the next directive or by the end of the program.
Because directives must follow the executable code in your program, you put that code first. In this case, the executable code creates a new dinosaur, Dino, that is an instance of the Dinosaur class. Rexx then runs the INIT method. Rexx runs any INIT method automatically whenever the NEW message is received. Here the INIT method is used to identify the type of dinosaur. Then the program runs the DIET method to determine whether the dinosaur eats meat or vegetables. Rexx saves the information returned by INIT and DIET as variables in the Dino object.
In the example, the Dinosaur class and its two methods are defined following the executable program code:
dino=.dinosaur~new /* Create a new dinosaur instance and /* initialize variables */ dino~diet /* Run the DIET method */ exit
::class Dinosaur /* Create the Dinosaur class */ ::method init /* Create the INIT method */ expose type say "Enter a type of dinosaur." pull type return ::method diet /* Create the DIET method */ expose type select when type="T-REX" then string="Meat-eater" when type="TYRANNOSAUR" then string="Meat-eater" when type="TYRANNOSAURUS REX" then string="Meat-eater" when type="DILOPHOSAUR" then string="Meat-eater" when type="VELICORAPTOR" then string="Meat-eater" when type="RAPTOR" then string="Meat-eater" when type="ALLOSAUR" then string="Meat-eater" when type="BRONTOSAUR" then string="Plant-eater" when type="BRACHIOSAUR" then string="Plant-eater" when type="STEGOSAUR" then string="Plant-eater" otherwise string="Type of dinosaur or diet unknown" end say string return 0