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

initialization meeting notes

In this message I try to summarize what we agreed at the meeting in
Boston.  The basis for this message is the 4 pages of notes which Sonya
took and which Sonya, Dave and I went over just before the meeting
ended.  I have tried to include in this message only what we actually
agreed on.  I will send out my comments and suggestions in a separate

First, a brief summary of what we agreed:

 -  there will be a :initarg slot option

 -  will will support remote initarg defaulting by having an
    defclass option like :default-initargs.

 -  there will be a procedural model of how the whole thing
    works.  Extensions to initialization behavior other than
    simple-slot-filling-initargs and initarg-remote-defaulting
    will be done by defining a method on the appropriate generic

Another important thing which we agreed is that we are going to have to
go back and re-examine our rules for argument list congruence.  The
existing rules clearly get in our way for doing initialization.  In a
separate message I will try to summarize those problems.

In the meeting, we put up some code for make-instance and
initialize-instance.  I am including that here:

(defmethod make-instance ((class-name 'symbol) &rest initargs)
  (apply #'make-instance (class-named class-name) initargs))

(defmethod make-instance ((class standard-class) &rest initargs)
  (let* ((proto (class-prototype class))
	 (defaulted-initargs (default-initargs proto initargs)))
    (check-initargs class defaulted-initargs)
    (let ((instance (apply #'allocate-instance class defaulted-initargs)))
      (apply #'initialize-instance instance defaulted-initargs)

(defmethod initialize-instance ((obj object) &rest initargs)
  ;; The default initialize-instance method deals with setting the
  ;; values of slots from slot-filling-initargs and from initforms.
  ;; The rules are that the leftmost initarg which is declared
  ;; as setting a slot (with the :initarg slot option) actually
  ;; does set it (or is it the rightmost?); and that slots which
  ;; are not set by an initarg have their :initform evaluated and
  ;; used to set them.

An effect of putting the slot setting stuff in the default method on
initialize-instance is that most programmers will want to define their
initialize-instance methods as :after methods.  This means an instance
will get initialized in order from most general to least general.

The default method for default-initargs implements the initarg remote
defaulting behavior using the :default-initargs class option.

The default method for check-initargs checks the validity of the
initargs by checking two sources:
  1. an initarg is valid if it is specified as a slot-filling initarg.

  2. an initarg is valid if it is specified as a &key argument in
     one of the applicable methods on initialize-instance.

Here is an example of a use of this protocol:

(defclass ship ()
    ((x :initarg :x)
     (y :initarg :y)))

(defmethod initialize-instance :after ((s ship) &key startp)
  (when startp (start s)))

(defmethod start ((s ship))
  (with-slots ((s :use-accesors nil))
    (if (and x y)
        <start it up>
        (error "Have to set X and Y before starting a ship."))))

(defclass homing-ship (ship)
     :x 0
     :y 0))

(defmethod home ((s homing-ship))
  (with-slots ((s :use-accessors nil))
     (setq x 0 y 0)))

We also agreed that there would be documented functions for finding out
about the initargs that set slots for a class and also finding out about
the default initargs for a class.   This doesn't seem to be too hard;
the only serious problem has to do with arranging for a the default
initarg value forms to be evaluated in the lexical environment of the
defclass. (Of course if environments were first class objects this would
be trivial...)