[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
initialization protocol
- To: Common-Lisp-Object-System@Sail.Stanford.edu
- Subject: initialization protocol
- From: Gregor.pa@Xerox.COM
- Date: 4 Feb 87 19:37 PST
- Cc: Gregor.pa@Xerox.COM
Here is my proposed initialization protocol. It is based on the
one I sent out before. Like that protocol, the primary goals are
simplicity and flexibility. This proposal also includes some comments
about the conventions for use of this protocol.
There are two major changes in this protocol:
1.) there is a system-supplied initialize method which processes
the &rest argument to make-instance as plist of slot names
and values. This method initializes the slots of the instance
from the values in this plist, any slot for which no value
is specified in the plist is initialized from the default
value specified in the defclass form. This change provides
the user with access to the canned functionality of treating
the &rest argument to make-instance as a plist of slot-names
and values. It provides it in a way that Moon seems to like
in which the :initforms in the defclass are only evaluated
when no value for the slot is specified in the &rest argument
to make-instance.
2.) initialize take the &rest argument which was passed to
make-instance as a single argument rather than an &rest or
&key argument. This is the part of this protocol I am the
least attached to. If we want to change this so that
make-instance uses apply to call initialize I am amenable
to that. The reason I have done it this way is to avoid the
pain of always having to add:
(.. &rest options &key &allow-other-keys)
to initialize methods.
Here is some prototype code which implements this protocol. I am
using this code here because it is simple, and it makes it exactly
clear what happens when.
(defmethod make-instance ((class-name symbol) &rest options)
(apply #'make-instance (class-named class-name) options))
(defmethod make-instance ((class class) &rest options)
(let ((instance (make-instance-internal class)))
(initialize instance options)
instance))
(defmethod initialize ((o object) options)
(dolist (slot-name (all-slots (class-of o)))
(setf (slot-value o slot-name)
(let* ((getf-default (list nil))
(plist-value (getf options slot-name getf-default)))
(if (eq plist-value getf-default)
(evaluate-initform o slot-name)
plist-value)))))
The convention for the &rest argument to make-instance (which I will
call the init-plist but someone else is free to invent a better term) is
as follows:
It should be a true plist, the keys (odd-numbered elements of
the list) should be either:
slot-names, in which case the default initialize method (or
some user-defined initialize method will initialize the
slots from those values
keywords, a keyword implies that the initialize method is
going to do more "work" than just set the slot value (with
slot value). Things specified with keywords are often
compound values or values which don't map directly onto
slot values.
Here are some sample initialize methods. These show some standard stuff
people might want to do:
(defmethod initialize ((p plane) options)
(when options (error "Planes accept no init-plist")))
(defmethod initialize ((b boat) options)
(call-next-method) ;first do slot values
(when (cadr (memq options ':start)) ;then start if we should
(start boat)))
;;; note that the flet with apply used in this example is the downside
;;; of the decision to pass the options to initialize as one argument.
;;; as I said above, I think this is worth it.
(defmethod initialize ((m method) options)
;; We do hairy processing to set function specializers and
;; qualifiers in parallel. So we accept those as keywords.
(flet ((internal (&key function specializers qualifiers)
(setf (slot-value m 'function) function
(slot-value m 'specializers) specializers
(slot-value m 'qualifiers) qualifiers)
.. code to process the new values in parallel ..))
(apply #'internal options)))
;;; In this case, we want to process the options if there are any,
;;; but before we do so, we want to evaluate ALL the :initforms in
;;; the defclass and install them in the instance.
(defmethod initialize ((s ship) options)
(if (null options)
(call-next-method)
(progn
(initialize s ()) ;Go evaluate :initforms.
.. now process options ..)))
Some bugs (and answers) with my proposal:
B: The convention of using flet and apply is weird.
A: Its no so bad really, and its much better than having to say
&rest options &key &allow-other-keys all over
B: The default initialize method only signals an error if the
init-plist has an even number of elements. If the user
wants to implement complete error-checking of the init-plist
they have to do it themselves.
A: Right. Doing complete error checking of the init-plist
involves checking the values too, so if the user is going
to do that they will have no more code to write to check
the keys.
Please, speak now...