[Openmcl-devel] MOP initialize-instance question
Cyrus Harmon
ch-openmcl at bobobeach.com
Mon Sep 13 09:02:08 PDT 2004
Wow. Lots of details to digest. I like the way this looks. A cursory
glance suggests that the more-moppish-s-i would do what I want by
calling slot-value-using-class.
Thanks for yet another great in-depth explanation of my (latest)
problem!
Cyrus
On Sep 13, 2004, at 3:09 AM, Gary Byers wrote:
>
>
> On Mon, 13 Sep 2004, Cyrus Harmon wrote:
>
>> So I'm trying to make my own metaclasses and I have a class that has a
>> mix of some "special" slots and some standard slots. I can get
>> slot-value-using-class and setf s-v-u-c to work properly, but I can't
>> figure out how to hijack the initargs stuff so the MOP code Does What
>> I
>> Mean. It would be nice if there were an initialize-slot that got
>> called
>> by initialize-instance (or %shared-initialize). But there doesn't seem
>> to be. Any suggestions for how I can get slot-specific (or even
>> direct-slot-definition-specific) behavior so I can use the built-in
>> stuff for "normal" slots and do my own work to figure out what the
>> values (and where they should go are) for my non-normal slots?
>>
>> Is there a better way to skin this cat?
>>
>> Thanks,
>>
>> Cyrus
>>
>
> OpenMCL defines:
>
> (defmethod shared-initialize ((instance standard-object) slot-names
> &rest initargs)
> (declare (dynamic-extent initargs))
> (%shared-initialize instance slot-names initargs))
>
> e.g., the function CCL::%SHARED-INITIALIZE happens to do all of the
> heavy
> lifting.
>
> CCL::%SHARED-INITIALIZE does that heavy lifting under the assumption
> that it's dealing with standard objects that have standard slot
> definitions,
> and it bypasses most of the MOP in doing what it does, for two reasons:
>
> 1) Because It Can
> 2) Because most of the MOP doesn't necessarily exist until the methods/
> classes/etc in question can be initialized with, and this function is
> used to initialize those objects.
>
> After CLOS has initialized itself (it's mostly all there by the time
> that "ccl:level-1;l1-clos" has finished loading during XLOAD-LEVEL-0),
> reason 2 becomes less compelling; it'd be possible to redefine
> CCL::%SHARED-INITIALIZE (mostly) in terms of MOP functions:
>
> (defun more-moppish-%shared-initialize (instance slot-names initargs)
> (unless (or (listp slot-names) (eq slot-names t))
> (report-bad-arg slot-names '(or list (eql t))))
>
> ;; Check that initargs contains valid key/value pairs,
> ;; signal a PROGRAM-ERROR otherwise. (Yes, this is
> ;; an obscure way to do so.)
>
> (destructuring-bind (&key &allow-other-keys) initargs)
>
> ;; I'm not sure if there's a more portable way of detecting
> ;; obsolete instances. This'll eventually call
> ;; UPDATE-INSTANCE-FOR-REDEFINED-CLASS if it needs to.
>
> (let* ((wrapper (instance-class-wrapper instance))
> (class (%wrapper-class wrapper)))
> (when (eql 0 (%wrapper-hash-index wrapper)) ; obsolete
> (update-obsolete-instance instance))
>
> ;; Now loop over all of the class's effective slot definitions.
>
> (dolist (slotd (class-slots class))
>
> ;; Anything that inherits from STANDARD-EFFECTIVE-SLOT-DEFINITION
> ;; in OpenMCL will have a CCL::TYPE-PREDICATE slot, derived from
> ;; the slot's specified TYPE. This check for slot existence
> ;; and -boundp-ness is probably overkill: it's not well-defined
> ;; to try to inherit from EFFECTIVE-SLOT-DEFINITION without
> ;; also inheriting from STANDARD-EFFECTIVE-SLOT-DEFINITION,
> ;; and these checks might slow things down a bit.
>
> (let* ((predicate
> (if (and (slot-exists-p slotd 'type-predicate)
> (slot-boundp slotd 'type-predicate))
> (slot-value slotd 'type-predicate)
> #'true)))
> (multiple-value-bind (ignore new-value foundp)
> (get-properties initargs (slot-definition-initargs slotd))
> (declare (ignore ignore))
> (cond (foundp
>
> ;; an initarg for the slot was passed to this function
> ;; Typecheck the new-value, then call
> ;; (SETF SLOT-VALUE-USING-CLASS)
>
> (unless (funcall predicate new-value)
> (error 'bad-slot-type-from-initarg
> :slot-definition slotd
> :instance instance
> :datum new-value
> :expected-type (slot-definition-type slotd)
> :initarg-name (car foundp)))
> (setf (slot-value-using-class class instance slotd)
> new-value))
> ((and (or (eq slot-names t)
> (member (slot-definition-name slotd)
> slot-names
> :test #'eq))
> (not (slot-boundp-using-class class instance
> slotd)))
>
> ;; If the slot name is among the specified slot names,
> or
> ;; we're reinitializing all slots, and the slot is
> currently
> ;; unbound in the instance, set the slot's value based
> ;; on the initfunction (which captures the :INITFORM).
>
> (let* ((initfunction (slot-definition-initfunction
> slotd)))
> (if initfunction
> (let* ((newval (funcall initfunction)))
> (unless (funcall predicate newval)
> (error 'bad-slot-type-from-initform
> :slot-definition slotd
> :expected-type (slot-definition-type
> slotd)
> :datum newval
> :instance instance))
> (setf (slot-value-using-class class instance
> slotd)
> newval))))))))))
> instance)
>
> This is basically a slightly re-written version of
> CCL::%SHARED-INITIALIZE, with a few more comments and with lower-level
> accessors that know lots about the representation of STANDARD-OBJECTs
> replaced with more general MOP functions where possible (and quite
> possibly with a few bugs introduced; save important work before trying
> to use this, and don't be shocked if args are backwards or parens are
> misplaced ...)
>
> Although this -could- be used as a replacement for
> CCL::%SHARED-INITIALIZE after things are bootstrapped, there are some
> tradeoffs involved. If we're dealing with things that are
> semantically far-removed from STANDARD-OBJECT, some concepts may not
> apply (the SHARED-INITIALIZE method that Randall Beer wrote for the
> ObjC bridge had to deal with the fact that ObjC has no real concept of
> "boundp-ness" and that ObjC may not even like the idea of instance
> reinitialization too much.) Likewise, the typechecking that happens
> on standard objects may not apply (or be desirable) in some cases.
>
> If the objects in question are "standard" CLOS objects with standard
> semantics, skipping the MOP's generality makes instance initialization
> a little faster, which is probably A Good Thing. (Perhaps the right
> thing is to use the current version of CCL::%SHARED-INITIALIZE if
> the metaclass of the instance is STANDARD-CLASS or
> FUNCALLABLE-STANDARD-
> CLASS exactly, and fall back on the more general case if it's a
> subclass
> of one of those classes.)
>
>
More information about the Openmcl-devel
mailing list