From: Slava Akhmechet
Subject: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <87fy5ee7vt.fsf@gmail.com>
I am trying to add custom behavior to slot access by specializing
slot-value-using-class. Specifically, I want to add classes whose slot
values have been modified to a list of "dirty" classes. My code works
properly on SBCL but I run into problems on OpenMCL.

As mentioned elsewhere, OpenMCL optimizes away slot-value-using-class
within let forms[1]. I wasn't able to find any information about
turning off this optimization. Lispworks provides
':optimize-slot-access' option in class definition, is there something
similar in OpenMCL?

Elephant seems to support OpenMCL, so there must be a way to do
this. Unfortunately it seems that information is rather scarce.

[1] Curiously, this seems to work when the accessed slot symbol is in
a different package. However, variables declared as special in the let
form can't seem to be accessed from the specialized version of
slot-value-using-class.

-- 
Regards,
Slava Akhmechet.

From: Pascal Costanza
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <5c5ge8F2u8oivU1@mid.individual.net>
Slava Akhmechet wrote:
> I am trying to add custom behavior to slot access by specializing
> slot-value-using-class. Specifically, I want to add classes whose slot
> values have been modified to a list of "dirty" classes. My code works
> properly on SBCL but I run into problems on OpenMCL.
> 
> As mentioned elsewhere, OpenMCL optimizes away slot-value-using-class
> within let forms[1]. I wasn't able to find any information about
> turning off this optimization. Lispworks provides
> ':optimize-slot-access' option in class definition, is there something
> similar in OpenMCL?
> 
> Elephant seems to support OpenMCL, so there must be a way to do
> this. Unfortunately it seems that information is rather scarce.

One hint: When you specializer slot-value-using-class (and the other 
slot access functions), you have to make sure that at least either the 
class or the slot definition parameter is specialized. It is not enough 
to only specialize the object parameter. So for example, the following 
is incorrect:

(defmethod slot-value-using-class
   (class (object myclass) slotd)
   ...)

You should at least do this:

(defmethod slot-value-using-class
   ((class mymetaclass) object slotd)
   ...)

Unfortunately, the wording in the CLOS MOP specification is imprecise 
here, but OpenMCL is one of the implementations that interprets it like 
that. So OpenMCL optimizes away calls to slot-value-using-class when 
neither the class nor the slot definition parameter are specialized, and 
doesn't make any effort to check for specialization of the object 
parameter. (For example, SBCL doesn't perform this kind of optimization, 
that's why your code works there.)

IMHO, the CLOS MOP specification should drop this requirement, but 
that's a different story.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slava Akhmechet
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <87bqg2e4ew.fsf@gmail.com>
Pascal Costanza <··@p-cos.net> writes:

> (defmethod slot-value-using-class
>   ((class mymetaclass) object slotd)
>   ...)
Ah, I see. Does this work with standard-class? I seem to be getting
inconsistant results (works in a simple testcase but not in my
codebase). Am I required to specify a custom metaclass? If this is the
case, could you give a very simple example of how to define a class
with custom metaclass? I don't have the AMOP book and there seems to
be almost no information on this online.

-- 
Regards,
Slava Akhmechet.
From: Pascal Costanza
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <5c60vqF2up10bU1@mid.individual.net>
Slava Akhmechet wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> (defmethod slot-value-using-class
>>   ((class mymetaclass) object slotd)
>>   ...)
> Ah, I see. Does this work with standard-class? I seem to be getting
> inconsistant results (works in a simple testcase but not in my
> codebase). Am I required to specify a custom metaclass? If this is the
> case, could you give a very simple example of how to define a class
> with custom metaclass? I don't have the AMOP book and there seems to
> be almost no information on this online.

You are not allowed to change the behavior of predefined metaclasses 
(and also not that of predefined classes, by the way). Otherwise a CLOS 
implementation would have a very hard time to optimize its internal 
default behavior.

The idiom to introduce your own metaclass is this:

(defclass mymetaclass (standard-class)
   ())

(defmethod validate-superclass
   ((class mymetaclass) (superclass standard-class))
   "this is necessary so that you can inherit from other classes"
   t)

(defmethod slot-value-using-class
   ((class mymetaclass) object slot)
   ...)

...same for the other slot-xyz-using-class functions.

It is sometimes useful to distinguish between default slot access and 
customized slot access even in your own metaclasses. For that, you can 
introduce new slot definition classes:

(defclass my-effective-slot-definition
   (standard-effective-slot-definition)
   ())

(defmethod effective-slot-definition-class
   ((class mymetaclass) &rest initargs)
   (if ... some condition ...
     (find-class 'my-effective-slot-definition)
     (find-class 'standard-effective-slot-definition)))

...and then specialize slot-value-using-class additionally on the new 
slot definition metaclass:

(defmethod slot-value-using-class
   ((class mymetaclass) object (slot my-effective-slot-definition))
   ...)

I hope this helps. You can find the CLOS MOP specification at 
http://www.lisp.org/mop/


Cheers,
Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slava Akhmechet
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <87bqg2yonk.fsf@gmail.com>
Pascal Costanza <··@p-cos.net> writes:

> I hope this helps.
Thank you, it helps a lot! I just tried the fix and it works.  I only
have one last question. Why are metaclasses are not inherited?

(defclass a ()
  (slot)
  (:metaclass somemeta))

(defclass b ()
  (slot2))

Metaclass of 'b' will be standard-class (which causes problems). I
manually added the metaclass declaration to all relevant class, but is
there a way to simply propagate it from base class?

-- 
Regards,
Slava Akhmechet.
From: Larry Clapp
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <slrnf5ruhr.pe3.larry@theclapp.ddts.net>
On 2007-05-30, Slava Akhmechet <·········@gmail.com> wrote:
> Pascal Costanza <··@p-cos.net> writes:
>> I hope this helps.
> Thank you, it helps a lot! I just tried the fix and it works.  I
> only have one last question. Why are metaclasses are not inherited?
>
> (defclass a ()
>   (slot)
>   (:metaclass somemeta))
>
> (defclass b ()
>   (slot2))
>
> Metaclass of 'b' will be standard-class (which causes problems). I
> manually added the metaclass declaration to all relevant class, but
> is there a way to simply propagate it from base class?

I'm not Pascal, but did you mean

(defclass b (a)
  (slot2)) ;^^^

?

As far as why it's not inherited, I don't know for sure, but it seems
to me that the inheritance of metaclass in the presence of multiple
inheritance would be very complex.

You'd probably do better to write a define-somemeta macro along the
lines of:

(defmacro define-somemeta (name &body body)
  `(defclass ,name 
      ,@body
      (:metaclass somemeta)))

(untested)

-- Larry
From: Slava Akhmechet
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <873b1dzzh1.fsf@gmail.com>
Larry Clapp <·····@theclapp.org> writes:

> I'm not Pascal, but did you mean
>
> (defclass b (a)
>   (slot2)) ;^^^
Yes, thank you!

> As far as why it's not inherited, I don't know for sure, but it seems
> to me that the inheritance of metaclass in the presence of multiple
> inheritance would be very complex.
That makes sense. Now that you brought it up, metaclasses in the
presence of multiple inheritance seems like a very complex issue even
without metaclass inheritance :)

-- 
Regards,
Slava Akhmechet.
From: Pascal Costanza
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <5c6ee4F2vp5mfU1@mid.individual.net>
Slava Akhmechet wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> I hope this helps.
> Thank you, it helps a lot! I just tried the fix and it works.  I only
> have one last question. Why are metaclasses are not inherited?

There is no simple and straightforward to way integrate this into CLOS 
because of multiple inheritance and also forward referenced classes. It 
would also be conceptually weird, IMHO.

> Metaclass of 'b' will be standard-class (which causes problems). I
> manually added the metaclass declaration to all relevant class, but is
> there a way to simply propagate it from base class?

What seems to be done a lot is (a) to provide your variant of the 
defclass macro that automatically insert the right :metaclass option for 
you and sometimes even (b) to shadow cl:defclass. In this way you can 
ensure that all classes in your system have the same customized metaclass.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: CoffeeMug
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <1181798957.587735.125830@j4g2000prf.googlegroups.com>
On May 30, 3:18 pm, Pascal Costanza <····@p-cos.net> wrote:
> It is sometimes useful to distinguish between default slot access and
> customized slot access even in your own metaclasses. For that, you can
> introduce new slot definition classes:
>
> (defclass my-effective-slot-definition
>    (standard-effective-slot-definition)
>    ())
>
> (defmethod effective-slot-definition-class
>    ((class mymetaclass) &rest initargs)
>    (if ... some condition ...
>      (find-class 'my-effective-slot-definition)
>      (find-class 'standard-effective-slot-definition)))
>
> ...and then specialize slot-value-using-class additionally on the new
> slot definition metaclass:
>
> (defmethod slot-value-using-class
>    ((class mymetaclass) object (slot my-effective-slot-definition))
>    ...)
How can I change the class of effective slot definition for a
particular slot, not for all slots that belong to a class with a
specific metaclass? For example, if I want to specialize slot-value-
using-class only for a slot with a certain name, I'd have to ensure
that the effective class is different only for that slot. Is there a
way to do that? Effective-slot-definition-class seems to be the wrong
method for the job.

Regards,
- Slava Akhmechet
From: Pascal Costanza
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <5dc9kkF341ie5U1@mid.individual.net>
CoffeeMug wrote:
> On May 30, 3:18 pm, Pascal Costanza <····@p-cos.net> wrote:
>> It is sometimes useful to distinguish between default slot access and
>> customized slot access even in your own metaclasses. For that, you can
>> introduce new slot definition classes:
>>
>> (defclass my-effective-slot-definition
>>    (standard-effective-slot-definition)
>>    ())
>>
>> (defmethod effective-slot-definition-class
>>    ((class mymetaclass) &rest initargs)
>>    (if ... some condition ...
>>      (find-class 'my-effective-slot-definition)
>>      (find-class 'standard-effective-slot-definition)))
>>
>> ...and then specialize slot-value-using-class additionally on the new
>> slot definition metaclass:
>>
>> (defmethod slot-value-using-class
>>    ((class mymetaclass) object (slot my-effective-slot-definition))
>>    ...)
> How can I change the class of effective slot definition for a
> particular slot, not for all slots that belong to a class with a
> specific metaclass? For example, if I want to specialize slot-value-
> using-class only for a slot with a certain name, I'd have to ensure
> that the effective class is different only for that slot. Is there a
> way to do that? Effective-slot-definition-class seems to be the wrong
> method for the job.

The CLOS MOP is missing a direct way to do this. However, you can use a 
workaround: (1) Define a special variable that holds the effective slot 
definition class, (2) make effective-slot-definition-class return the 
contents of that special variable, and (3) bind the variable in 
compute-effective-slot-definition.

Here is a rough sketch:

(defvar *effective-slot-definition-class*)

(defmethod effective-slot-definition-class
            ((class myclass) &key &allow-other-keys)
   *effective-slot-definition-class*)

(defmethod compute-effective-slot-definition
            ((class myclass) name direct-slot-definitions)
   (let ((*effective-slot-definition-class*
          (if (eq name 'foo)
            (find-class 'my-effective-slot-definition)
            (find-class 'standard-effective-slot-definition))))
     (call-next-method)))

This works because the CLOS MOP guarantees that 
effective-slot-definition-class is called as part of the default method 
for compute-effective-slot-definition.

This also allows you to base the selection of the effective slot 
definition class on other properties of the direct slot definitions. For 
example, it is relatively straightforward to test for the settings of 
custom slot options in compute-effective-slot-definition, if they have 
been recorded in your own direct slot definition class.

I hope this helps.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Slava Akhmechet
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <874placwbz.fsf@gmail.com>
Pascal Costanza <··@p-cos.net> writes:

> The CLOS MOP is missing a direct way to do this. However, you can use
> a workaround: (1) Define a special variable that holds the effective
> slot definition class, (2) make effective-slot-definition-class return
> the contents of that special variable, and (3) bind the variable in
> compute-effective-slot-definition.
Actually, after some more investigation I am now thinking this is not
an appropriate way to achieve what I want. It's probably better to add
an option to a direct definition so that the user can simply specify
it as part of slot declaration in defclass and then copy it over to
effective definition.

CLOS seems to be designed for such extensions, while my original
intention feels more like a hack.

-- 
Regards,
Slava Akhmechet.
From: Pascal Costanza
Subject: Re: Specializing slot-value-using-class in OpenMCL
Date: 
Message-ID: <5dddavF34fnghU1@mid.individual.net>
Slava Akhmechet wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>> The CLOS MOP is missing a direct way to do this. However, you can use
>> a workaround: (1) Define a special variable that holds the effective
>> slot definition class, (2) make effective-slot-definition-class return
>> the contents of that special variable, and (3) bind the variable in
>> compute-effective-slot-definition.
> Actually, after some more investigation I am now thinking this is not
> an appropriate way to achieve what I want. It's probably better to add
> an option to a direct definition so that the user can simply specify
> it as part of slot declaration in defclass and then copy it over to
> effective definition.
> 
> CLOS seems to be designed for such extensions, while my original
> intention feels more like a hack.

Using explicit slot options instead of implicit "magic" names is indeed 
a better way in the general case. However, it is also a good idea to 
only use custom effective slot definition classes when you actually need 
them. The reason is that CLOS yields much better performance when it 
knows that only the default methods on s-v-u-c are applicable - it can 
effectively circumvent calling s-v-u-c altogether and perform a direct 
access on the slot itself. So using standard-effective-slot-definition 
when you only need the standard behavior is a good idea.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/