next up previous contents
Next: The Object Precedence Up: Multiple Inheritance Previous: A Simple Approach

Shared Object Parts

 

In order to avoid multiple instantiations of an object part, it is necessary to test for every instantiation of an object part, whether the part already has been instantiated. This section shows how this problem is dealt with.

Let me as the starting point introduce the template of a class with multiple super classes, which uses the precedence list representation of objects.

 

(define (class-name parts)
(let ((super (super-class-list parts super-class-name ... ))
(self ()))
(let ((instance-variable init-value)
...)

(define (method formal-parameter...)
method-body)
...

(define (dispatch message)
(cond ((eqv? message class-id) class-name)
((eqv? message super-classes) super)
((eqv? message selector) method)
...
(else ())))

(set! self (class-handle dispatch super))
self)))

Overall, a class describes how to instantiate the super parts of the class. This is programmed in the procedure super-class-list , which returns a list of object parts, where each part is represented as an object precedence list (see gif and gif).

If no sharing of parts is involved, super-class-list

``asks the super class to instantiate itself'' in the normal way (by calling the Scheme procedure underlying the class). If, however, super-class-list finds out that a superclass already has been instantiated once, the object precedence list representation is reconstructed from the existing part and, in turn, its super parts.

In more details, there are a number of new elements in the class template compared with that from section gif:

  1. The parts parameter.
    The procedure which simulates a class takes a parameter called parts . During the instantiation of the class, this parameter is supposed to contain a list of already instantiated parts.

  2. Super is bound to the result of a call to super-class-list .
    The procedure super-class-list replaces the procedure new-part-list in the superclass definition clause. Super-class-list instantiates the super parts of the object, and it ensures that no part of the object is instantiated more than once.

  3. An object can return its class.
    Given the selector class-id gif, dispatch responds with the lambda expression of the procedure, which implements the class. In other words, it is possible for an object obj

    to return the class of which it is an instance. It can be done via the following procedure call: (method-lookup obj class-id) , which at the end of this section will be abstracted to (class-of-object obj) .

  4. An object can return its super objects.
    Similarly, an object can return the list of super objects, which are referred to by super. This can be done with (method-lookup object super-classes) , or with the procedure supers-of-object , which will be defined later in this section.

  5. Simplified response on non-matching message in dispatch .
    In the else clause of dispatch there is no method lookup to the super class. Rather, dispatch returns the empty list if the message ``falls through'' the dispatch procedure. This is because objects are represented as precedence lists of object parts (see section gif.)

  6. Change of the assignment of self .
    Self is assigned to the result of (class-handle dispatch super)

    at the end of the procedure. Class-handle returns an object precedence list when the class is instantiated. The description of class-handle is postponed to section gif.

Because of the parts parameter, it is necessary to introduce a slightly changed version of the class instantiation primitive, new-instance .

 

(define (new-instance class)
  (let ((instance (class ())))
    (virtual-operations instance)
    instance))

In the rest of this section I will describe how the procedure super-class-list , together with the procedures on which it depends, can be implemented. Recall that the purpose of super-class-list is to instantiate the super parts of the actual object part, and to avoid multiple instantiations of the same object part.

The procedure super-class-list is just syntactic sugar for super-class-list-1 , which is more convenient to work with because it has a fixed number of parameters.

   

(define (super-class-list existing-parts . class-list)
  (super-class-list-1 existing-parts class-list))

(define (super-class-list-1 existing-parts class-list)
  (if (null? class-list)
      ()
      (let ((parts (instantiate-super-class
                    existing-parts
                    (car class-list))))
        (cons parts
              (super-class-list-1
               (append parts existing-parts)
               (cdr class-list))))))

Super-class-list-1 basically maps the procedure instantiate-super-class on each class in class-list . During this mapping, it keeps track of already instantiated parts in its first parameter.

Before it is explained how instantiate-super-class works, let us look at a simple example of how the class instantiation proceeds. The example is based on the class hierarchy shown in figure gif(a). The call (new-instance d)

first instantiates the b branch of the class hierarchy. When instantiating the c branch, existing-parts refers to a list of the b-part and the a-part, which are the already existing parts of the object. During the instantiation of the c branch it can be discovered that the a-part shouldn't be instantiated again.

Instantiate-super-class is defined in the following way:

 

(define (instantiate-super-class existing-parts class)
  (let ((prev-i (previous-instantiation class existing-parts)))
    (if prev-i
        (class-handle prev-i 
                      (supers-of-object prev-i))
        (class existing-parts))))

It uses the procedure previous-instantiation to test whether there exists an instantiation of class in existing-parts . If no such instantiation exists, class is instantiated and returned. The result of this instantiation is an object precedence list (see section gif). If class already has been instantiated, a reconstruction of the existing object part is returned. At the Scheme level, prev-i becomes bound to the dispatch procedure (self ) of the already existing instance. In order to reconstruct the object precedence list representation of the object, I also need information about the super objects of the object. The list of super parts (represented as object precedence lists) is returned by the procedure supers-of-object .

   

(define (supers-of-object object)
  (method-lookup-single-object object super-classes))

(define (method-lookup-single-object object message)
  (object message))

Based on ``self and super information'', class-handle can reconstruct the precedence list of the already existing object part.

In the procedure previous-instantiation , it is necessary to be able to tell whether a given object is an instance of a given class.

   

(define (is-class-of? class object)
  (eq? class (class-of-object object)))

(define (class-of-object object)
  (method-lookup-single-object object class-id))

Is-class-of? uses a function class-of-object , which for a given object returns its class---a lambda expression at the implementation language level. In Scheme, it is possible to compare two procedures for equality using eqv? .

Previous-instantiation can now test if a class already is instantiated in the following way:

 

(define (previous-instantiation class existing-parts)
  (let ((res (memb is-class-of?
                   class
                   existing-parts)))
    (if res
        (car res)
        #f)))

If, according to existing-parts , class already has been instantiated it returns the already existing part (which also serves as true.) Else it returns false.

Memb is similar to the Scheme primitive member . Memb tests whether an element is a member of a list using an explicitly passed comparison procedure.

 

(define (memb comparison obj plist)
  (cond ((null? plist) #f)
        ((comparison obj (car plist)) plist)
        (else (memb comparison obj (cdr plist)))))

Thus, (memb is-class-of? c object-parts) tests whether an object in the list object-parts is an instance of the class c .



next up previous contents
Next: The Object Precedence Up: Multiple Inheritance Previous: A Simple Approach



Kurt Noermark
Wed Mar 6 10:30:05 MET 1996