As explained above, the description of the method lookup process is distributed across the various dispatching procedures in the classes. The procedure method-lookup is only syntactic sugar for the procedure call, which realizes the method lookup in another object part. If a given procedure dispatch cannot find a selector that matches a message, it propagates the lookup to the dispatch procedure of the super part of the object. This is done via a (recursive) call to the procedure method-lookup . In this section I will describe an alternative representation of objects that allows this propagation process to be described in a single procedure.
The idea is to represent an object as a list
of parts (concretely as a list of dispatch
procedures)
instead of as a single part. Let us assume that is a class,
and that the superclass of
is
, i =
.
Given these assumptions, we want to represent an
instance of
as the list
where -part, at the Scheme level, is the dispatch procedure of a
object part. This list will be called the object
precedence list (or just the precedence list) of the object.
Given the new representation of objects, it is necessary to modify both the dispatch procedure and the assignment of self . Let me show a class template under the assumption that objects are represented as precedence lists of parts.
(define (class-name)
(let ((super (new-part super-class))
(self ()))
(let ((instance-variable init-value)
...)
(define (method formal-parameter...)
method-body)
...
(define (dispatch message)
(cond ((eqv? message selector) method)
...
(else ())))
(set! self (class-handle dispatch super)))
self))
As of here, class-handle can be defined to be an alias for cons .
(define class-handle cons)
(Class-handle dispatch super) returns a list, the head of which is dispatch , and with a tail that is the object precedence list of the super part of the object (returned by another incarnation of class-handle
via the procedure new-part
.)
In section , class-handle
will be redefined to
handle the changes introduced by having multiple superclasses.
Notice that dispatch no longer propagates messages to the super part of the object. If a message isn't mapped to a method in dispatch , the dispatching procedure returns the empty list.
The procedure method-lookup now has to be redefined. Method-lookup is not used directly in the class definition any more, but it is, among other places, used in the send primitive.
(define (method-lookup object-precedence-list message) (let ((result (linear-search object-precedence-list (lambda (object) (method-lookup-single-part object message))))) (method-lookup-single-part result message))) (define (method-lookup-single-part object message) (object message)) (define (linear-search list found?) (if (found? (car list)) (car list) (linear-search (cdr list) found?)))
Method-lookup is implemented as a linear search on object-precedence-list . The object precedence list is searched for a part, which responds to the given message. The auxiliary procedure method-lookup-single-part
serves a dual role. It is used rather directly in the predicate passed to the linear search procedure, and it is used on the result of the search to locate the method. (This is possible in Scheme, because of the relatively free interpretation of boolean values).
Both the message sending primitive send and the instantiation primitive new-instance survive the shift of object representation.
The advantages of the precedence list representation of
objects, as introduced in this section, are not great compared
with the original representation. If, however, we introduce
multiple inheritance it turns out that the precedence list
representation is better suited than the more simple representation.
I will come back to that in section .
Until then the precedence list representation will not be used.