From: levy
Subject: CLOS meta class
Date: 
Message-ID: <1146512626.513543.238510@i39g2000cwa.googlegroups.com>
Hi,

Is there a way to have a CLOS class being its own meta class? The
reasons for doing that are quite complicated, so I would just skip them
this time.

There is cleary at least one, namely standard-class, but all the
trivial tries failed for me on SBCL:

(defclass x (standard-class) () (:metaclass x))

or

(defclass x (standard-class) ())
(ensure-class 'x :metaclass 'x)

or with inheritance
(defclass x (standard-class) ())
(defclass y (x) (:metaclass x))

and some more complicated ways, etc.

Maybe I need to use the internal APIs, but maybe it will just screw up
things...

Any idea?

levy

From: Pascal Costanza
Subject: Re: CLOS meta class
Date: 
Message-ID: <4bncveF12ebbpU1@individual.net>
levy wrote:
> Hi,
> 
> Is there a way to have a CLOS class being its own meta class? The
> reasons for doing that are quite complicated, so I would just skip them
> this time.
> 
> There is cleary at least one, namely standard-class, but all the
> trivial tries failed for me on SBCL:
> 
> (defclass x (standard-class) () (:metaclass x))
> 
> or
> 
> (defclass x (standard-class) ())
> (ensure-class 'x :metaclass 'x)
> 
> or with inheritance
> (defclass x (standard-class) ())
> (defclass y (x) (:metaclass x))
> 
> and some more complicated ways, etc.
> 
> Maybe I need to use the internal APIs, but maybe it will just screw up
> things...
> 
> Any idea?

This will probably not work. The reason why standard-class is an 
instance of itself is that the metaclass-hierarchy needs a "base case", 
like all recursive descriptions of systems. Consider:

(defun fac (n)
   (if (zerop n)
      1
      (* n (fac (- n 1)))))

This is a recursive process, and it only works because at some stage the 
recursive process stops since it has a reasonable base case. The same 
goes for CLOS: A class is an instance of a class which is an instance of 
a class, etc., and this only works since the whole hierarchy of classes 
has a reasonable base case.

However, this means that at the implementation level, you have to do 
some cheating because you have to make sure that something can refer to 
itself. For recursive functions, a compiler has to announce that a 
function exists before it is fully defined, and for standard-class a 
CLOS implementation also has to announce that it exists before it is 
fully defined. However, the CLOS MOP doesn't give you the means to do 
this yourself, at least not within the specified framework.

If you want to know how this works, and to get an idea of how hackerish 
the cheating is to make this work in the first place, you can take a 
look at Closette which is described in the AMOP book (and can also be 
found online at several places), or also Tiny CLOS for Scheme which is 
somewhat neater. You would basically need a way to directly modify the 
link to the class of a class object.


Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/
From: levy
Subject: Re: CLOS meta class
Date: 
Message-ID: <1146559796.894104.222040@i39g2000cwa.googlegroups.com>
I understand your points and I have guessed things work like that and
that's why the trivial versions did not work. I can actually live with
some kind of hackish solution, because this is a very short and well
known code that makes my life easier in hundreds of other places. The
meta class which I want to have being its own metaclass is pretty
similar to standard-class in what its role is in the system, so I think
I'm not trying to misuse the concepts.

Thanks for your help, I will take a look at the mentioned stuff and
probably also how SBCL handles this internally. I guess setting some
internal slots on the class meta object and maybe calling some internal
functions might do it.

levy
From: Steven M. Haflich
Subject: Re: CLOS meta class
Date: 
Message-ID: <T4g6g.72714$H71.39151@newssvr13.news.prodigy.com>
Pascal Costanza wrote:

> This is a recursive process, and it only works because at some stage the 
> recursive process stops since it has a reasonable base case. The same 
> goes for CLOS: A class is an instance of a class which is an instance of 
> a class, etc., and this only works since the whole hierarchy of classes 
> has a reasonable base case.
> 
> However, this means that at the implementation level, you have to do 
> some cheating because you have to make sure that something can refer to 
> itself.

I believe no cheating is necessary.  The canonic solution to this
metacircularity problem involves simple use of change-class:

cl-user(2): (defclass my-standard-class (standard-class) ())
#<standard-class my-standard-class>
cl-user(3): (change-class * 'my-standard-class)
#<my-standard-class my-standard-class>
From: Pascal Costanza
Subject: Re: CLOS meta class
Date: 
Message-ID: <4bthacF1339leU1@individual.net>
Steven M. Haflich wrote:
> Pascal Costanza wrote:
> 
>> This is a recursive process, and it only works because at some stage 
>> the recursive process stops since it has a reasonable base case. The 
>> same goes for CLOS: A class is an instance of a class which is an 
>> instance of a class, etc., and this only works since the whole 
>> hierarchy of classes has a reasonable base case.
>>
>> However, this means that at the implementation level, you have to do 
>> some cheating because you have to make sure that something can refer 
>> to itself.
> 
> I believe no cheating is necessary.  The canonic solution to this
> metacircularity problem involves simple use of change-class:
> 
> cl-user(2): (defclass my-standard-class (standard-class) ())
> #<standard-class my-standard-class>
> cl-user(3): (change-class * 'my-standard-class)
> #<my-standard-class my-standard-class>


This violates the CLOS MOP specification which states that portable 
programs must not use change-class on class metaobjects. (Of course, 
this might still be good enough for the OP's needs.)


Pascal

-- 
3rd European Lisp Workshop
July 3-4 - Nantes, France - co-located with ECOOP 2006
http://lisp-ecoop06.bknr.net/