From: Willem Broekema
Subject: Changing a class' metaclass
Date: 
Message-ID: <993e16d4-d52c-4ee4-b398-17fe73896e90@k13g2000hse.googlegroups.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.

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

From: John Thingstad
Subject: Re: Changing a class' metaclass
Date: 
Message-ID: <op.ubb135eaut4oq5@pandora.alfanett.no>
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
From: Pascal Costanza
Subject: Re: Changing a class' metaclass
Date: 
Message-ID: <69a8s7F319m57U1@mid.individual.net>
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/