next prev up top content index

6 Functions

Method Dispatch

When a generic function is called, the generic function uses the types of the arguments to determine which methods to call. This process is called method dispatch.

Method dispatch occurs in three phases. First, all the applicable methods are selected. Next, the applicable methods are sorted by specificity. Finally, the most specific method is called.

Method Specificity

For any two methods A and B that are applicable to a given generic function call, one method may be more specific than the other, or the methods may be ambiguous methods.

To order two methods A and B with respect to a particular set of arguments, compare each of A's specializers with B's specializer in the corresponding position using the argument that was supplied for that position. The comparison works in the following way.

The method A is more specific than the method B if and only if A precedes B in at least one argument position, and B does not precede A in any argument position. Similarly, B is more specific than A if and only if B precedes A in at least one argument position, and A does not precede B in any argument position. If neither of these cases apply then A and B are ambiguous methods.

When the applicable methods are sorted by specificity, the sorted list is divided into two parts, each possibly empty. The first part contains methods that are more specific than every method that follows them. The second part (which cannot itself be sorted) begins at the first point of ambiguity; there are at least two methods that could equally well go first in the second part. When a generic function is called, if the first part of the sorted applicable methods is empty then an error is signaled. Similarly, if the last method in the first part attempts to call next-method, an error is signaled.

Consider the following class definitions:

define class <sentient> (<life-form>) end class;
define class <bipedal> (<life-form>) end class;
define class <intelligent> (<sentient>) end class;
define class <humanoid> (<bipedal>) end class;
define class <vulcan> (<intelligent>, <humanoid>) end class; 

Computing the class precedence list for <vulcan> yields

#(<vulcan>,<intelligent>,<sentient>,<humanoid>,<bipedal>,<life-form>)

The class precedence lists computed for two different classes may have different precedence orders for some intermediate superclasses. This is not a problem as long as there is no class that inherits from both classes. For example, we could define a class <human> as follows:

define class <human> (<humanoid>, <intelligent>) end class;

For the class <human> defined as above, the class precedence list would be

#(<human>,<humanoid>,<bipedal>,<intelligent>,<sentient>,<life-form>)

It is not a problem that the two class precedence lists give different orders to some of the intermediate superclasses such as <bipedal> and <sentient> as long as no class is added that inherits from both <vulcan> and <human>.

When sorting the applicable methods, each specializer needs to be viewed with respect to the class precedence list for the class of the argument passed to the generic function in that argument position. For example, given the following definitions

define method psychoanalyze (being :: <intelligent>)
  …
end method;
define method psychoanalyze (being :: <humanoid>) 
  …
end method;

calling the generic function psychoanalyze on a being of type <human> would cause the method for <humanoid> to be called first, while calling the generic function on a being of type <vulcan> would cause the method for <intelligent> to be called first.

The order of arguments is not significant when computing method specificity. Given the above class definitions, the following methods are unambiguous when their generic function is called on two beings of type <vulcan> or two beings of type <human>, but the methods are ambiguous when the call includes one being of type <vulcan> and one of type <human>.

define method superior-being (a :: <intelligent>,
                              b :: <intelligent>) 
  most-intelligent-being (a, b)
  end method;
define method superior-being (a :: <humanoid>,
                              b :: <humanoid>)
  best-looking-being (a, b)
  end method;

Calling Less Specific Methods

In many situations, a subtype wants to modify the behavior of a method, rather than replace it completely; it wants to perform some work but also use the inherited behavior. This can be accomplished with next-method. Next-method is a function that, when called, invokes the next most specific method applicable in the generic function. The next-method is the value of the #next parameter. Normally this parameter is named next-method, though it can have other names at the programmer's discretion.

One can think of next-method as invoking the method that would have been called if the current method did not exist.

If there are no more methods available, the next-method parameter will be bound to the value #f instead of to a method.

Passing Different Arguments to Next-Method

In the usual case, next-method is called with no arguments. This indicates that the next-method should be passed the same arguments that were supplied to the current method.

It is valid to supply arguments, including different arguments, when calling next-method. However, if you pass different arguments, the new arguments must result in the same ordered sequence of applicable methods as the original arguments. Otherwise, the program behavior is undefined.

In some cases, the methods in a generic function accept different keyword arguments. In such cases, it's convenient for the methods also to accept a rest parameter. That way, all the keyword/value pairs passed to the generic function are captured in the rest parameter. By using apply, the next-method can be invoked with the complete set of arguments. (This technique is only necessary, of course, when the method calls next-method and passes arguments explicitly.)

As usual, if there are duplicates of a given keyword argument, the leftmost occurrence is used. This allows keyword arguments to be easily overridden.

The Next-Method Parameter

The value of the next-method parameter is supplied by the generic function dispatch mechanism. When a method is called by its generic function, the generic function dispatch mechanism automatically passes the appropriate value for next-method. There is no way for a user program to specify the next-method argument when calling a method.

If you create a method directly (i.e., with method rather than with define method) and you want this method to accept a next-method parameter, then you should insert a #next into the parameter list explicitly. You would do this if you are creating a method that you plan to add to a generic function, and you want this method to be able to call next-method. You can also supply the next-method parameter when using define method, in cases where you want to give the parameter a different name.