Some people might have wondered whether it is possible to change the
metaclass of a class. The MOP seems to clearly disallow it, but
nevertheless some implementations do allow it. Here are the details:
"Some class metaobject classes allow their instances to be redefined.
When permissible, this is done by calling reinitialize-instance. This
is discussed in the next section."
<http://www.lisp.org/mop/concepts.html#init-class>
"Some class metaobject classes allow their instances to be
reinitialized. This is done by calling reinitialize-instance. The
initialization arguments have the same interpretation as in class
initialization." <http://www.lisp.org/mop/concepts.html#reinit-class>
But reinitialize-instance is just for slots, it does not accept
a :metaclass option. So that won't work.
Maybe changing the metaclass can be done using ensure-class, which
forwards to ensure-class-using-class, and there we have:
"If the class of the class argument is not the same as the class
specified by the :metaclass argument, an error is signaled." <http://
www.lisp.org/mop/dictionary.html#ensure-class-using-class>
That is a clear NO.
SBCL 1.0.16 confirms it:
* (defclass my-metaclass (standard-class) ())
#<STANDARD-CLASS MY-METACLASS>
* (defclass foo (standard-class)())
#<STANDARD-CLASS FOO>
* (sb-pcl:ensure-class 'foo :metaclass 'my-metaclass)
debugger invoked on a SB-PCL::METAOBJECT-INITIALIZATION-VIOLATION:
Cannot CHANGE-CLASS objects into CLASS metaobjects.
See also:
AMOP, Initialization of Class Metaobjects
Nevertheless, Allegro 8.1 does accept it:
cl-user(2): (defclass my-metaclass (standard-class) ())
#<standard-class my-metaclass>
cl-user(3): (defclass foo (standard-class)())
#<standard-class foo>
cl-user(4): (mop:ensure-class 'foo :metaclass 'my-metaclass)
#<my-metaclass foo>
as does Lispworks 5.0.2:
CL-USER 2 > (defclass my-metaclass (standard-class) ())
#<STANDARD-CLASS MY-METACLASS 2009BDA3>
CL-USER 3 > (defclass foo (standard-class)())
#<STANDARD-CLASS FOO 200B7C3F>
CL-USER 4 > (defmethod clos:validate-superclass ((class my-metaclass)
superclass)
(declare (ignorable class superclass))
t)
#<STANDARD-METHOD VALIDATE-SUPERCLASS NIL (MY-METACLASS T) 200A01B3>
CL-USER 5 > (clos:ensure-class 'foo :metaclass 'my-metaclass)
#<MY-METACLASS FOO 200B7C3F>
- Willem
P� Sat, 17 May 2008 13:37:15 +0200, skrev Willem Broekema
<········@gmail.com>:
> Some people might have wondered whether it is possible to change the
> metaclass of a class. The MOP seems to clearly disallow it, but
> nevertheless some implementations do allow it. Here are the details:
>
> "Some class metaobject classes allow their instances to be redefined.
> When permissible, this is done by calling reinitialize-instance. This
> is discussed in the next section."
> <http://www.lisp.org/mop/concepts.html#init-class>
>
> "Some class metaobject classes allow their instances to be
> reinitialized. This is done by calling reinitialize-instance. The
> initialization arguments have the same interpretation as in class
> initialization." <http://www.lisp.org/mop/concepts.html#reinit-class>
>
> But reinitialize-instance is just for slots, it does not accept
> a :metaclass option. So that won't work.
>
> Maybe changing the metaclass can be done using ensure-class, which
> forwards to ensure-class-using-class, and there we have:
>
> "If the class of the class argument is not the same as the class
> specified by the :metaclass argument, an error is signaled." <http://
> www.lisp.org/mop/dictionary.html#ensure-class-using-class>
>
> That is a clear NO.
>
MOP is enforced by protocol. That is a user is allowed the power of
meta-classes, but is responsible for enforcing the assumptions on which
this freedom was given. For instance the introspection functions could
also allow you to change class properties. This is, however, not a good
idea. The implementor of MOP is allowed considerable freedom in how to
implement the MOP. Thus the behaviour outside the 'contract' is
unpredictable and non-portable.
--------------
John Thingstad
Willem Broekema wrote:
> Some people might have wondered whether it is possible to change the
> metaclass of a class. The MOP seems to clearly disallow it, but
> nevertheless some implementations do allow it. Here are the details:
>
> "Some class metaobject classes allow their instances to be redefined.
> When permissible, this is done by calling reinitialize-instance. This
> is discussed in the next section."
> <http://www.lisp.org/mop/concepts.html#init-class>
>
> "Some class metaobject classes allow their instances to be
> reinitialized. This is done by calling reinitialize-instance. The
> initialization arguments have the same interpretation as in class
> initialization." <http://www.lisp.org/mop/concepts.html#reinit-class>
>
> But reinitialize-instance is just for slots, it does not accept
> a :metaclass option. So that won't work.
>
> Maybe changing the metaclass can be done using ensure-class, which
> forwards to ensure-class-using-class, and there we have:
>
> "If the class of the class argument is not the same as the class
> specified by the :metaclass argument, an error is signaled." <http://
> www.lisp.org/mop/dictionary.html#ensure-class-using-class>
>
> That is a clear NO.
A natural hook to do this would be change-class on a class metaobject.
However, the CLOS MOP also clearly says this: "Portable programs must
not call change-class to change the class of any class metaobject or to
turn a non-class object into a class metaobject."
The tricky part is not necessarily in the mechanics of replacing the
class pointer in a class metaobject, but rather that there is no
protocol for updating instances. update-instance-for-different-class is
not quite sufficient I think, because it doesn't cover the instances of
instances. (Hm, how would you word that better...?)
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/