Object-Oriented Methods

DESCRIPTION:
Object-oriented features in S-PLUS provide a mechanism that readily allows one function to be used to process many different classes of data. Such a function is called a generic function, and it, in turn, calls a different method function for each class of objects that it accepts.

INTRODUCTION:
Method functions are named by concatenating the name of the generic function, ".", and the name of a class of S-PLUS objects; for example, the object print.factor would be a method for evaluating the function print on an object of class factor. We say that print.factor is a matching method for function print and class factor.

Methods are invoked (from a generic function) in one of three ways: from a call to UseMethod in an S-PLUS function; from internal code invoked through the .Internal interface; or from a call to NextMethod contained in another method. When a method is invoked, a special part of the S-PLUS evaluator, called the dispatcher is used.


UseMethod:
When a function calls UseMethod, the dispatcher looks at the class of an object in the current frame. By default and typically this is the first argument of the current function. The search begins with the value (as a character vector) of the class attribute of the object. This vector gives the various classes of objects from which the object inherits properties. In addition, all objects implicitly inherit from class default. Each of the classes in the inheritance is examined, in order, looking for a method that matches the current function and that class. The first match obtained causes that method to be evaluated.

amp;.Internal:
Generic functions using the .Internal interface have their default method contained in the internal code.

When the dispatcher is invoked from a .Internal interface the matching mechanism is the same, with one addition and one exception. The addition is that methods can be defined and matched for the entire group of functions corresponding to a single internal interface. For example, all the functions using the Math interface can be matched for class factor by defining a method Math.factor. These functions include sin, abs and many others (see the reference for a table of all the groups and corresponding functions). The two other important groups are Ops (all operators) and Summary.

The exception is that for operators (arithmetic, comparison and logical) and [potentially] for functions with arbitrary numbers of arguments like c, the dispatcher looks for a single method that consistently matches all the relevant arguments. More precisely, all the arguments for which there is a non-default matching method must match to the same method. For example, suppose there is a method, Ops.factor, to handle all operators for class factor. Then x+y will use Ops.factor if Ops.factor is the matching method for both x and y, or if Ops.factor matches for one of x or y and there is no matching method for the other operand. The method code in Ops.factor is responsible for knowing which operands had matching methods and (because it is a group method) for knowing that "+" was the generic function. The special objects .Method and .Generic provide the needed information (see below).

Each group of generic functions consists of all of the functions that are .Internal calls to a specific routine. For example the Math group is internal calls to "do_math", Summary is calls to "do_summary", and the Ops group is calls to "do_op". Other less important groups (and the internal code that they call) are Extract ("S_extract"), Replace ("S_replace"), As ("As_vector"), and Is ("Is_vector"). There are a few other calls to .Internal that support generic functions, these are noted in the appropriate help files.


NextMethod:
When the dispatcher is invoked from NextMethod, it starts the matching from the position of the current method in the object's class attribute. Suppose the method print.factor is being evaluated for an object thing with a class attribute as follows: > class(thing) [1] "ordered" "factor" "other" Now we encounter a call to NextMethod. The dispatcher will find the current class, "factor", in the inheritance and look next for a method print.other. The two points to keep in mind are: (1) the dispatcher makes no change to the object's class attribute; and (2) the search for a next method always starts from the position of the current class.

THE FRAME:
When a method is invoked from the dispatcher, it is evaluated in a frame containing all the arguments to the generic function. The objects in the frame have their values as of the time of the call to the method. That is, if changes are made before the call to UseMethod or to NextMethod, these changes will be reflected in the values seen in the new frame. Objects assigned in the frame other than the arguments are not transmitted to the method.

In addition to the arguments, the following special objects will exist in the frame of the method:

.Class:
the class of the object that caused this method to be invoked.
.Method:
a character vector whose elements give the name(s) of the method used. Its primary value is in methods for operators: here the vector has length 2 (for infix operators) and its elements are either the name of the method or the empty string. Thus methods typically use nchar(.Method[i]) to decide which of the operands belongs to the relevant class of objects.
.Group:
a character vector giving the name of the group for a group method, or an empty string.
.Generic:
a character string giving the name of the generic function. Its use is primarily in group methods that need to know which of the functions in the group they're dealing with.

REFERENCES:
Chambers, J. M. and Hastie, T. J. (1991). Statistical Models in S. Wadsworth & Brooks/Cole, Pacific Grove, CA. (Appendix A)

SEE ALSO:
UseMethod , class .