More about Methods

A method name can be any character string. When an object receives a message, Rexx searches for a method whose name matches the message name.

You must surround a method name with quotation marks when it is the same as an operator. The following example illustrates how to do this correctly. It creates a new class (Cost), defines a new method (%), creates an instance of the Cost class (Mycost), and sends a % message to Mycost:


mycost = Cost~new           /* Creates new instance mycost.*/
mycost~"%"                  /* Sends % message to mycost.  */

::class Cost subclass "Retail" /* Creates Cost, a sub-     */
                               /* class of "Retail" class. */
  ::method "%"                 /* Creates % method.        */
    expose p                   /* Produces: Enter a price. */
    say "Enter a price"        /* If the user specifies a  */
    pull p                     /* price of 100,            */
    say p*1.07                 /* produces: 107            */
    return 0

The Default Search Order for Selecting a Method

When a message is sent to an object, Rexx looks for a method whose name matches the message string. If the message is ADD, for example, Rexx looks for a method named ADD. Because, in the class hierarchy, there may be more than one method with the same name, Rexx begins its search at the object specified in the message. If the sought method is not found there, the search continues up the hierarchy. Rexx searches in the following order:

  1. A method the object defines itself (with SETMETHOD or ENHANCED).

  2. A method the object's class defines.

    An object acquires the methods of its parent class; that is, the class for which the object was created. If the class subsequently receives new methods, objects predating the new methods do not acquire them.

  3. A method an object's superclasses define.

    As with the object's class, only methods that existed in the superclass when the object was created are valid. Rexx searches the superclass method definitions in the order that INHERIT messages were sent to an object's class.

If Rexx does not find a match for the message name, Rexx checks the object for method name UNKNOWN. If it exists, Rexx calls the UNKNOWN method, and returns whatever the UNKNOWN method returns. For more information on the UNKNOWN method, see Defining an UNKNOWN Method. If the object does not have an UNKNOWN method, Rexx raises a NOMETHOD condition. Any trapped information can then be inspected using Rexx's CONDITION built-in function.

Rexx searches up the hierarchy so that methods existing in higher levels can be supplemented or overridden by methods existing in lower levels.

Figure 6-4. Searching the Hierarchy for a Method

For example, suppose you wrote a program that allows users to look up other users' phone numbers. Your program includes a class called Phone_Directory, and all its instances are users' names with phone numbers. You have included a method in Phone_Directory called NOTIFY that reports some data to a file whenever someone looks up a number. All instances of Phone_Directory use the NOTIFY method.

Now you decide you want NOTIFY, in addition to its normal handling, to personally inform you whenever anyone looks up your number. To accommodate this special case for your name only, you create your own NOTIFY method that adds the new task and replicates the file-handling task. You save the new method as part of your own name instance, retaining the same name, NOTIFY.

Now, when a NOTIFY message is sent to your name instance, the new version of NOTIFY is found first. Rexx does not look further up the class hierarchy. The instance-level version overrides the version at the class level. This technique of overriding lets you change a method used by one instance without disturbing the common method used by all the other instances. It is very powerful for that reason.

Changing the Search Order for Methods

When composing a message, you can change the default search order for methods by doing both of the following:

  1. Making the receiver object the sender object. You usually do this by specifying the special variable SELF. SELF holds the value of the object in which a method is running. You can use SELF to run another method in an object where a method is already running or pass references about an object to the methods of other objects.

  2. Specifying a colon and a class symbol after the message name. The class symbol identifies the class object to use as the starting point for the search. This class object must be:

    • A direct superclass of the class that defines the active method

    • The object's own class, if you used SETMETHOD to define the active method

      The class symbol is usually the special variable SUPER, but it can be any environment symbol or variable name whose value is a valid class.

In A Sample Program Using Directives, an Account subclass of the Object superclass is created. It defines a TYPE method for Account, and creates the Savings subclass of Account. The example defines a TYPE method for the Savings subclass, as follows:

::class Savings subclass Account

  ::method "TYPE"
    return "a savings account"

To change the search order so Rexx searches for TYPE in the Account rather than Savings subclass, enter this instead:

  ::method "TYPE"
    return self~type:super "(savings)"

When you create an asav instance of the Savings subclass and send a TYPE message to asav:

say asav~type

Rexx displays:

an account

rather than:

a savings account

because Rexx searches for TYPE in the Account class first.

Public versus Private Methods

A method can be public or private. Any object can send a message that runs a public method. Only a message an object sends to itself, using the special variable SELF as the message receiver, can run a private method. Private methods include methods at different scopes within the same object. This allows superclasses to make methods available to their subclasses while hiding those methods from other objects. A private method is like an internal subroutine. It shields the internal information of an object.

Defining an UNKNOWN Method

When an object that receives a message has no matching message name, Rexx checks if the object has a method named UNKNOWN. If it does, Rexx calls UNKNOWN, passing two arguments. The first is the name of the method that was not located. The second is an array containing the arguments passed with the original message.

To define an UNKNOWN message, you specify:

UNKNOWN(message_name,message_args)