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 a 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.
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.
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
"S_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.
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.
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:
nchar(.Method[i])
to decide which
of the operands belongs to the relevant class of objects.
Chambers, J. M. and Hastie, T. J. (1991). Statistical Models in S. Wadsworth & Brooks/Cole, Pacific Grove, CA. (Appendix A)