[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

change to instance structure protocol

   From: rpg@lucid.com

   I believe you are proposing the Telos (EuLisp) solution.


Almost, but there is at least one important difference.  In TELOS, the
slot access protocol has one more level than in CLOS.  SLOT-VALUE is
defined as follows:

(defun slot-value (object slot-name &optional no-error-p)
  ;; Returns the value of the slot named SLOT-NAME in the object. If
  ;; NO-ERROR-P is () and the value is the unbound slot value,
  ;; SLOT-UNBOUND will be called with the object and slot name as
  ;; arguments.  If NO-ERROR-P is true, the value will always be
  ;; returned, even if it is unbound.  If the slot does not exist,
  ;; SLOT-MISSING will be called with the object and slot name as
  ;; arguments, irrespective of NO-ERR-FLAG.
  (let* ((slotd (find-slot (class-of object) slot-name))
         (original-value (slot-description-reader slotd object)))
    (if no-error-p
      (if (eq original-value (unbound-slot-value))
	  (slot-unbound object slot-name)

FIND-SLOT is responsible for reporting SLOT-MISSING.  It is a generic
function discriminating on the object's metaclass.

SLOT-DESCRIPTION-READER is a generic function whose methods normally
discriminate on the class of the slot definition object.  In typical
cases, it calls EuLisp's equivalent of SLOT-VALUE-USING-CLASS,
METACLASS-SLOT-READER. (I don't like the names either.)  This generic
function is handed the class of the object, the object, and a third
object which indicates the position of the slot in the object.  In
typical implementations, this third object is an integer.

The point of this scheme is that the slot definition object has a
chance to get a handle on the slot access before the metaclass, and
can ignore the metaclass's normal slot access behavior.  A typical
example of the use of the two levels is shared slots:

(defmethod slot-description-reader ((slotd local-slot-description) object)
  ;; This is the typical case where we let the metaclass take control
  (metaclass-slot-reader (class-of object) object
                         (slot-description-position slotd)))

(defmethod slot-description-reader ((slotd shared-slot-description) object)
  ;; This is for shared slots.  In this case, the slot description
  ;; holds a pointer to a vector of shared slot values for the class
  ;; which defined the slot.  METACLASS-SLOT-READER is not called.
  (vector-ref (slot-description-shared-values slotd)
              (slot-description-position slotd)))

So the metaclass only comes into play when the slot description
decides it's appropriate.  At first glance, you might think that
giving the slot description class priority over the metaclass can be
accomplished using Gregor's scheme as well by respecifying the
argument precedence order.  However, the advantage of the EuLisp
scheme is not just the order in which things are done, but the fact
that you can write methods for slot description classes and
metaclasses separately.  Mix-n-match, as it were.

To go along with this upgrade of the slot description status (compared
to CLOS), there is an additional slot option in DEFCLASS which permits
the author to specify the class of the slot description for that slot.
This is more fine-grained than CLOS's EFFECTIVE-SLOT-DEFINITION-CLASS,
although I suppose it wouldn't be hard to write a metaclass in CLOS
which handled this option.  But STANDARD-CLASS's behavior does not
encourage the development of new slot description classes.

EuLisp also defines the function INDEXED-SLOT-VALUE, which skips the
SLOT-DESCRIPTION-READER phase of the access and goes directly to
METACLASS-SLOT-READER.  This can be used for homogenous objects of
arbitrary size, a case difficult to do properly in CLOS.  It is
defined as follows:

(defun indexed-slot-value (object position &optional no-error-p)
  ;; Retrieves the POSITION'th component of OBJECT using
  (let ((original-value (metaclass-slot-reader (class-of object)
                                               object position)))
   (if no-error-p
     (if (eq original-value (unbound-slot-value))
         (slot-unbound object position)

So there is a wide variety of object access possible for the user.

As with Gregor's method, standard optimization tricks are feasible in

-- Harley