[Openmcl-devel] initializing objects that are created elsewhere
gb at clozure.com
Sun Jan 9 21:25:20 UTC 2005
On Sun, 9 Jan 2005, alex crain wrote:
> My question about loading from nib files has turned into a more general
> OBJC problem.
> Any time an object is created on the OBJC side, it is not properly
> initialized on the lisp
> side, which means that if there are lisp slots, they don't get set up
> unless I do it explicitly.
> My latest example is with NSDocuments, which are created through the
> File menu.
> I have something like this:
> (defclass ide-editor-document (ns:ns-document)
> (window-controller-class :initform 'hemlock-window-controller
> :accessor document-window-controller)
> (textstorage :initform nil :accessor document-text-storage)
> (:metaclass ns:+ns-object))
> (defmethod initialize-instance :after ((doc ide-editor-document) &rest
> (declare (ignorable initargs))
> (setf (slot-value doc 'nib-name) "ide-editor")
> Which is fine if use MAKE-INSTANCE, but if I have IdeEditorDocument as
> a value in the
> Info.plist file, then clicking File->New causes OBJC to create the new
> object and all I get
> is a pointer to an uninitialized lisp object: no slots and
> INITIALIZE-INSTANCE is never run.
> In this case I just added (INITIALIZE-INSTANCE self) to the
> :makeWindowControllers method,
> but the programmer shouldn't have to figure out if an object has been
> initialized or not.
I'm not exactly sure what the last part of that sentence means.
> Somewhere, there is code that maps the external MACPTR to an object
> structure. That code
> knows what the object is and whether it already exists, so it should be
> able to handle this job.
There is code that maps MACPTRs to ObjC objects. I suppose that that
code could try to figure out whether the ObjC object had lisp slots and
whether any of them are unbound, and could maybe use some combination
of default-initargs and initforms to give those lisp slots values.
Currently, ALLOCATE-INSTANCE of an OBJC:OBJC-CLASS allocates an ObjC
instance and send it some flavor of "init" message (based on the
initargs.) It then determines if the class has any lisp slots; if
so, it allocates a "slots vector" for the lisp slots and associates
that slot vector with the instance. (Things are done in this order
because the "init" message may return a different instance from the
one that was allocated.)
If that slots-vector is missing, attempts to call SLOT-VALUE (or SETF of
it, or SLOT-BOUNDP, etc) on a lisp slot will fail and probably generate
a cryptic error message. It would probably make more sense if code
which looked for a foreign instance's slot-vector created one if it
didn't exist and should have; see the function %OBJC-DOMAIN-SLOTS-VECTOR
If the slots-vector was created lazily (and ALLOCATE-INSTANCE didn't
create it, or at least didn't do so unconditionally), it'd be possible
to do things like:
;; Set a lisp slot from an ObjC init method:
(define-objc-method ((id init) ide-editor-document)
(let* ((self (send-super 'init)))
(unless (%null-ptr-p self)
;; It would also be possible - if a bit confusing -
;; to call INITIALIZE-INSTANCE or SHARED-INITIALIZE here.
(setf (slot-value self 'nib-name) "ide-editor")
That -may- run afoul of the whole "init methods can return other
objects" problem in some cases; there may also be cases where some
class's initWithFoo:andBar: method never calls its init method.
That's maybe a step or two above calling INITIALIZE-INSTANCE in some
(more) random method like makeWindowControllers:. Because of when and
how lisp slots-vectors are initialized, it's generally not possible
to do this sort of thing in an ObjC "init..." method now.
> Can anyone give me a hint as to where to look?
There may be other approaches, but (so far) I like the idea of allocating
slots-vectors on demand. (The lack of a slots-vector for an ObjC instance
that should have lisp slots is a strong indication that INITIALIZE-INSTANCE
hasn't run yet.)
The idiom in the example above - initializing lisp slots after the
ObjC instance is initialized - would likely be a common one (if, ahem,
it worked.) If this were CLOS, one might want to create a mixin class
or define an :AFTER method on "init" or something; I'm not sure if there's
a good way to say "all init methods on lisp-implemented classes should
automatically initialize the lisp side of the instance" automatically,
but it'd certainly be nice to be able to do ad hoc lisp initialization
from an ObjC init method (and it's kind of hard to explain why you
currently can't, aside from "didn't think of it.")
More information about the Openmcl-devel