From: Alex Mizrahi
Subject: effective slot definitions
Date: 
Message-ID: <48e11faa$0$90272$14726298@news.sunsite.dk>
hi

i don't get how custom effective slot definitions
 mechanism is supposed to work by MOP standard.
i was able to find only implementation-specific
examples, and implementation-agnostic version seems
to be daunting.

let's consider a simple case -- we want some fancy
slot definition with additional slot initarg. e.g.:

(defclass fancy-slot-definition (standard-slot-definition)
  ((fancy :initarg :fancy :accessor fancy-of)))

it's supposed to work like this, in a class definition:

(defclass fancy-object ()
  ((slot1 :initarg :slot1)
   (slot2 :initarg :slot2 :fancy t))
 (:metaclass fancy-class))

slot1 should be a standard slot definition,
 and slot2 should be a fancy slot definition (slotd).

working with direct slotds is quite straightforward
 -- you just specialize direct-slot-definition-class
function for your metaclass, it accepts slot initargs
as parameter, and so you can see if slot is fancy or not.

situation with effective slot definitions looks quite similar
 -- you can specialize function
effective-slot-definition-class
 and/or compute-effective-slot-definition.

but it only looks so. information that effective-slot-definition-class
is sort of implementation specific (it depends on implementation of
default compute-effective-slot-definition function). in SBCL it
recieves only "standard" initargs, and effectively no information
that we can use to decide if slot is fancy or not.

so we'll have to override compute-effective-slot-definition -- 
either re-implementing all it's machinery, or somehow re-using
default return value. re-implementing compute-effective-slot-definition
is quite a daunting task -- in SBCL that's about 60 lines of code.
re-using value returned from default c-e-s-d ain't straightforward
 -- it seems one needs to call change-class on effective-slot-definition.

so i wonder, was it supposed to be that hard?

as for implementation-specific hacks, they are quite simple.
in Lispworks, effective-slot-definition-class recieves also
original initargs (besides computed ones), so it can decide which class it 
is.

in SBCL, one can use sb-pcl::compute-effective-slot-definition-initargs
to reuse most of c-e-s-d machinery, so overriding it goes less daunting.
From: Pascal Costanza
Subject: Re: effective slot definitions
Date: 
Message-ID: <6kd2ueF78r6iU1@mid.individual.net>
Alex Mizrahi wrote:
> hi
> 
> i don't get how custom effective slot definitions
>  mechanism is supposed to work by MOP standard.
> i was able to find only implementation-specific
> examples, and implementation-agnostic version seems
> to be daunting.
> 
> let's consider a simple case -- we want some fancy
> slot definition with additional slot initarg. e.g.:
> 
> (defclass fancy-slot-definition (standard-slot-definition)
>   ((fancy :initarg :fancy :accessor fancy-of)))
> 
> it's supposed to work like this, in a class definition:
> 
> (defclass fancy-object ()
>   ((slot1 :initarg :slot1)
>    (slot2 :initarg :slot2 :fancy t))
>  (:metaclass fancy-class))
> 
> slot1 should be a standard slot definition,
>  and slot2 should be a fancy slot definition (slotd).
> 
> working with direct slotds is quite straightforward
>  -- you just specialize direct-slot-definition-class
> function for your metaclass, it accepts slot initargs
> as parameter, and so you can see if slot is fancy or not.
> 
> situation with effective slot definitions looks quite similar
>  -- you can specialize function
> effective-slot-definition-class
>  and/or compute-effective-slot-definition.
> 
> but it only looks so. information that effective-slot-definition-class
> is sort of implementation specific (it depends on implementation of
> default compute-effective-slot-definition function). in SBCL it
> recieves only "standard" initargs, and effectively no information
> that we can use to decide if slot is fancy or not.
> 
> so we'll have to override compute-effective-slot-definition -- 
> either re-implementing all it's machinery, or somehow re-using
> default return value. 

You don't need to reimplement compute-effective-slot-definition. It's 
actually much simpler to use than you think.

Consider:

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

(defmethod effective-slot-definition-class
   ((class fancy-class) &key)
   *effective-slot-definition-class*)

(defmethod compute-effective-slot-definition
   ((class fancy-class) name direct-slots)
   (let ((*effective-slot-definition-class*
           (if (some #'fancy-of direct-slots)
             (find-class 'fancy-effective-slot-definition)
             (find-class 'standard-effective-slot-definition))))
     (call-next-method)))

You could also do the following:

(defmethod effective-slot-definition-class
   ((class fancy-class) &key)
   (find-class 'fancy-effective-slot-definition))

(defmethod compute-effective-slot-definition
   ((class fancy-class) name direct-slots)
   (let ((effective-slot (call-next-method)))
     (setf (fancy-of effective-slot)
           (some #'fancy-of direct-slots))
     effective-slot)))


...but I prefer not to use flags in effective slots, but rather use 
subclassing to indicate which features are supported or not, so that 
methods on slot-value-using-class etc. can be dispatched more 
efficiently (by specializing their slot arguments).


In order to make this approach work, fancy-of needs to work on standard 
slot definitions as well, but that's quite easy:

(defgeneric fancy-of (object)
   (:method ((object slot-definition)) nil))


You can find more elaborate examples in the source code of ContextL 
(special slots, layered slots, etc.).


BTW, I agree, compute-effective-slot-definition-initargs would make life 
somewhat easier. But the above approach is also portable and works fine 
across all the major CLOS MOP implementations I am aware of.



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/