6 Functions
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.
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 which 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 which 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;
One can think of next-method as invoking the method which 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.
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 occurance is used. This allows keyword arguments to be easily overridden.
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.
Generated with Harlequin WebMaker