[Openmcl-devel] metaclass problems with Elephant

Gary Byers gb at clozure.com
Wed Sep 14 09:03:10 PDT 2011


Before redefining the PERSISTENT-METACLASS class:

? (describe (find-class 'ele::default-slot-set))
#<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-SLOT-SET>
Class: #<STANDARD-CLASS ELEPHANT:PERSISTENT-METACLASS>
Wrapper: #<CLASS-WRAPPER ELEPHANT:PERSISTENT-METACLASS #x302000A556DD>
Instance slots
DIRECT-METHODS: NIL
PROTOTYPE: NIL
NAME: ELEPHANT::DEFAULT-SLOT-SET
PRECEDENCE-LIST: (#<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-SLOT-SET>
                   #<STANDARD-CLASS ELEPHANT::PSET-SLOT-SET>
                   #<STANDARD-CLASS ELEPHANT:SLOT-SET>
                   #<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-PSET>
                   #<STANDARD-CLASS ELEPHANT:PSET>
                   #<STANDARD-CLASS ELEPHANT:PERSISTENT-COLLECTION>
                   #<ELEPHANT:PERSISTENT-METACLASS ELEPHANT:PERSISTENT-OBJECT>
                   #<STANDARD-CLASS ELEPHANT:PERSISTENT>
                   #<STANDARD-CLASS STANDARD-OBJECT> #<BUILT-IN-CLASS T>)
OWN-WRAPPER: #<CLASS-WRAPPER ELEPHANT::DEFAULT-SLOT-SET #x302000BB947D>
DIRECT-SUPERCLASSES: (#<STANDARD-CLASS ELEPHANT::PSET-SLOT-SET>
                       #<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-PSET>)
DIRECT-SUBCLASSES: NIL
DEPENDENTS: NIL
CLASS-CTYPE: #<CLASS-CTYPE ELEPHANT::DEFAULT-SLOT-SET>
DIRECT-SLOTS: NIL
SLOTS: (#<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance slot ELEPHANT::OID #x302000BB96ED>
         #<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance slot ELEPHANT::SPEC #x302000BB964D>
         #<PERSISTENT-EFFECTIVE-SLOT-DEFINITION for instance slot ELEPHANT:BTREE #x302000BB953D>)
[...]

After redefining that class:

? (describe (find-class 'ele::default-slot-set))
#<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-SLOT-SET>
Class: #<STANDARD-CLASS ELEPHANT:PERSISTENT-METACLASS>
Wrapper: #<CLASS-WRAPPER ELEPHANT:PERSISTENT-METACLASS #x302000C8E88D>
Instance slots
DIRECT-METHODS: NIL
PROTOTYPE: NIL
NAME: ELEPHANT::DEFAULT-SLOT-SET
PRECEDENCE-LIST: (#<ELEPHANT:PERSISTENT-METACLASS ELEPHANT::DEFAULT-SLOT-SET>
                   #<ELEPHANT:PERSISTENT-METACLASS ELEPHANT:PERSISTENT-OBJECT>
                   #<STANDARD-CLASS STANDARD-OBJECT> #<BUILT-IN-CLASS T>)
OWN-WRAPPER: #<CLASS-WRAPPER ELEPHANT::DEFAULT-SLOT-SET #x302000CBD45D>
DIRECT-SUPERCLASSES: (#<ELEPHANT:PERSISTENT-METACLASS ELEPHANT:PERSISTENT-OBJECT>)
DIRECT-SUBCLASSES: NIL
DEPENDENTS: NIL
CLASS-CTYPE: #<CLASS-CTYPE ELEPHANT::DEFAULT-SLOT-SET>
DIRECT-SLOTS: NIL
SLOTS: NIL

Redefining the metaclass causes an instance of that metaclass (the
class ELE::DEFAULT-SLOT-SET) to become obsolete.  When we call
DESCRIBE on that obsolete instance, a variety of things happen,
including a call to SHARED-INITIALIZE.  Nothing's actually changed,
so when the code that handles this case of redefinition calls 
SHARED-INITIALIZE with an empty list of slot names and no initargs.

An :AROUND method on SHARED-INITIALIZE for PERSISTENT-METACLASS
computes a new value for the :DIRECT-SUPERCLASSES initarg and passes
that argument and value to the next method.  Doing this in other
contexts may make more sense than this seems to.

In CCL, an :AFTER method on SHARED-INITIALIZE takes effect when
:DIRECT-SUPERCLASSES is provided.  It processes that arg, in this
case changing the class's direct superclasses (and therefore its
CPL and in this case its effective slots.)  Doing that part of
class (re)initialization in a SHARED-INITIALIZE method is perhaps
questionable (if only because it's vulnerable to something like this,
but (a) it's not really clear that it's wrong and (b) it's not clear
why the Elephant code is saying "SHARED-INITIALIZE on a PERSISTENT-METACLASS
object should always pass the :DIRECT-SUPERCLASSES argument".

The more that I think about it, the more it seems that since I'm not
really sure what (SHARED-INITIALIZE class nil :DIRECT-SUPERCLASSES ...)
means, it'd be better to remove that :AFTER method and do what it does
elsewhere.  I don't know if there's another compelling reason to do that
(like "it's clearly wrong"), but there's no compelling reason to not
make the change, either.

You could have gotten a clearer idea of what was going on here just by
calling DESCRIBE; you can often get a fair amount of mileage out of the
use of simple, portable debugging tools like DESCRIBE and TRACE.

On Tue, 13 Sep 2011, Alex Mizrahi wrote:

> hi
>
> I'm one of developers of Elephant 'persistent object database' library
> (which heavily uses CLOS and MOP).
> I've recently discovered that Elephant does not work with recent
> versions of CCL, particularly, 1.7 and 1.6 IIRC.
> (Ian Eslick says that it was working with older versions, so I guess
> it is a regression.)
>
> After a long investigation of the problem it turned out that
> re-defining metaclass "fries" its classes, e.g. slots disappear,
> sometimes superclasses... scary stuff.
>
> Here's how to reproduce it:
>
> 1. Load elephant: (asdf:oos 'asdf:load-op :elephant)
> 2. Check that class slots are present:
>
> CL-USER> (class-slots (find-class 'ele::default-slot-set))
>
> (#<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance slot ELEPHANT::OID
> #x302000B5AB5D> #<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance
> slot ELEPHANT::SPEC #x302000B5AABD>
> #<PERSISTENT-EFFECTIVE-SLOT-DEFINITION for instance slot
> ELEPHANT:BTREE #x302000B5A9AD>)
> 3. Evaluate (defclass persistent-metaclass ...) in
> elephant/src/elephant/metaclasses.lisp
> 4. Confirm that slots are gone:
> CL-USER> (class-slots (find-class 'ele::default-slot-set))
> NIL
> 5. Finalizing class doesn't help it:
> CL-USER> (let ((ele::*warn-when-dropping-persistent-slots* nil))
> 	   (finalize-inheritance (find-class 'ele::default-slot-set)))
> NIL
> CL-USER> (class-slots (find-class 'ele::default-slot-set))
> NIL
> 6. But re-defining its super-class does: re-evaluate (defclass
> persistent-object ...) in elephant/src/elephant/classes.lisp
> Now slots are back:
> CL-USER> (class-slots (find-class 'ele::default-slot-set))
> (#<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance slot ELEPHANT::OID
> #x302000DFDFBD> #<TRANSIENT-EFFECTIVE-SLOT-DEFINITION for instance
> slot ELEPHANT::SPEC #x302000DFDBED>)
>
> I don't know any way to reproduce it which does not involve loading
> elephant (and I'm not even totally sure that this bug is not caused by
> some Elephant's mis-use of MOP), but perhaps information above is
> enough?
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>
>



More information about the Openmcl-devel mailing list