From: Albert Krewinkel
Subject: Methods or class allocated slots
Date: 
Message-ID: <fwu4pf7ev8b.fsf@pc09.inb.uni-luebeck.de>
Hi

I have a couple of classes whose instance-objects behave very similiar.
So in some cases it makes sense to let some slots be allocated to a
class, while in a few others classes those slots have to be allocated to
instances. Not a proplem per se, as CL makes this quite easy.

Now the following is what I was wondering about: How bad would it be to
just drop class slots and use method specializers instead? What's the
maximum number of instances for which it's okay to distinguish them
using eql-specifiers? When should there be an additional slot? Which one
is better in words of style?

I guess this depends on the implementation specifications for methods
and classes.  AMOP doesn't cover eql specializers, so I'm kind of lost
here.

Thanks for any pointers.

Albert

From: Thomas A. Russ
Subject: Re: Methods or class allocated slots
Date: 
Message-ID: <ymilk8ji63v.fsf@blackcat.isi.edu>
Albert Krewinkel <·········@natwiss.uni-luebeck.de> writes:

> Hi
> 
> I have a couple of classes whose instance-objects behave very similiar.
> So in some cases it makes sense to let some slots be allocated to a
> class, while in a few others classes those slots have to be allocated to
> instances. Not a proplem per se, as CL makes this quite easy.
> 
> Now the following is what I was wondering about: How bad would it be to
> just drop class slots and use method specializers instead? 

Here's where I stop understanding your argument.

It seems to me that class slots and method specializers solve different
problems.  The primary difference is that a slot provides some storage
location, which you don't get with methods, unless you allocate it
externally with a closure or global variable.  So, one could substitute
something like

 (let ((class-slot-substitute))
   (defmethod my-slot ((i my-class))
       class-slot-substitute)
   (defmethod (setf my-slot) (value (i my-class))
       ;; Can't remember if I got the arguments in the right order....
       (setq class-slot-subtitute value)))

but it seems that using a class slot is simpler to do.

> What's the
> maximum number of instances for which it's okay to distinguish them
> using eql-specifiers? 

I don't see how EQL specifiers figure into this at all.  You wouldn't
get class slots using EQL specifiers on methods, you would get something
more like individual slots.

> When should there be an additional slot? Which one
> is better in words of style?

I prefer class slots versus the lexical variable.  It is more compact,
appears directly in the class definition and just seems overall easier
to see what is going on.

> 
> I guess this depends on the implementation specifications for methods
> and classes.  AMOP doesn't cover eql specializers, so I'm kind of lost
> here.
> 
> Thanks for any pointers.
> 
> Albert

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Kent M Pitman
Subject: Re: Methods or class allocated slots
Date: 
Message-ID: <uprxvf5i9.fsf@nhplace.com>
···@sevak.isi.edu (Thomas A. Russ) writes:

>    (defmethod (setf my-slot) (value (i my-class))
>        ;; Can't remember if I got the arguments in the right order....

An aside relating to this comment:

You can puzzle this out when you don't remember.

The only reason the order of arguments is not the standard order is that
there would be no place to put it in the case of
  (setf (my-aref a i j k ...) value)
because you wouldn't have been able to write
  (defmethod (setf my-aref) (&rest indexes value) ...)
in the case that there was already a convention of taking any number of args.

So in order to have a workable protocol that was the same in all
cases, including the &rest case, we had to design it so that the value
arg would precede, not follow, the other args.

So yes, you got the arguments in the right order.
From: Albert Krewinkel
Subject: Re: Methods or class allocated slots
Date: 
Message-ID: <fwuaboy1qv2.fsf@pc09.inb.uni-luebeck.de>
···@sevak.isi.edu (Thomas A. Russ) writes:
> Albert Krewinkel <·········@natwiss.uni-luebeck.de> writes:
>> What's the
>> maximum number of instances for which it's okay to distinguish them
>> using eql-specifiers? 
>
> I don't see how EQL specifiers figure into this at all.  You wouldn't
> get class slots using EQL specifiers on methods, you would get something
> more like individual slots.

Yep, that's what I meant: If I have a class foo with a method

(defmethod some-property ((foo foo)) 42)

and a class bar for which `some-property' is different for each object,
one could do something like

(defclass bar () ((slot-a :initarg :a)))
(defmacro make-bar (a b)
  `(let ((new-bar (make-instance bar :a ,a)))
    (defmethod some-property ((foo (eql new-bar))) ,b)
    new-bar))

(make-bar 23 42)
=> #<BAR {D2572B9}>
(some-property *)
=> 42

Not very pretty, yes, but it would work (for some reason it looked much
better to me the first time I thought about it). Now how bad would it be
to do such thing? 

>
>> When should there be an additional slot? Which one
>> is better in words of style?
>
> I prefer class slots versus the lexical variable.  It is more compact,
> appears directly in the class definition and just seems overall easier
> to see what is going on.

I guess that answers the question.  First I thought it would be kind of
nice to reduce the need to define new classes, but now I see that it was
nothing but a brainfart.

Thanks for the answer though!

>> 
>> I guess this depends on the implementation specifications for methods
>> and classes.  AMOP doesn't cover eql specializers, so I'm kind of lost
>> here.
>> 
>> Thanks for any pointers.
>> 
>> Albert
>
> -- 
> Thomas A. Russ,  USC/Information Sciences Institute

-- 
Albert Krewinkel
From: Thomas A. Russ
Subject: Re: Methods or class allocated slots
Date: 
Message-ID: <ymihcj6i035.fsf@blackcat.isi.edu>
Albert Krewinkel <·········@natwiss.uni-luebeck.de> writes:

> ···@sevak.isi.edu (Thomas A. Russ) writes:
> > Albert Krewinkel <·········@natwiss.uni-luebeck.de> writes:
> >> What's the
> >> maximum number of instances for which it's okay to distinguish them
> >> using eql-specifiers? 
> >
> > I don't see how EQL specifiers figure into this at all.  You wouldn't
> > get class slots using EQL specifiers on methods, you would get something
> > more like individual slots.
> 
> Yep, that's what I meant: If I have a class foo with a method
> 
> (defmethod some-property ((foo foo)) 42)
> 
> and a class bar for which `some-property' is different for each object,
> one could do something like
> 
> (defclass bar () ((slot-a :initarg :a)))
> (defmacro make-bar (a b)
>   `(let ((new-bar (make-instance bar :a ,a)))
>     (defmethod some-property ((foo (eql new-bar))) ,b)
>     new-bar))
> 
> (make-bar 23 42)
> => #<BAR {D2572B9}>
> (some-property *)
> => 42
> 
> Not very pretty, yes, but it would work (for some reason it looked much
> better to me the first time I thought about it). Now how bad would it be
> to do such thing? 

Well, how about the following, much simpler solution:

  (defclass bar ()
     ((slot-a :initarg :a)
      (slot-b :initarg :some-property :reader some-property)))

  (make-instance 'bar :a a :some-property b)

Reader, writer and accessors for slots are just methods on a generic
function of that name, so you can have your SOME-PROPERTY method on
class FOO and then use slots with reader methods called SOME-PROPERTY on
class BAR as well.  Since they are all methods of the same generic
function, there isn't really any problem with doing this.

For information that would be read-only class slots it doesn't make much
difference if you implement them with a class slot or a method.  The
only place it makes a difference is if you want to be able to change the
value.  In that case class slots clearly make more sense.

If you want the value to be (potentially) different for each instance,
then using regular slots is the simplest solution.  Accessor methods are
really a conceptual construct.  Their actual realization is just as a
method on a generic function. (Although implementations may make some
other distinctions to allow for more efficiency -- but that isn't
visible at the API level).  One way to think about :reader methods is
that it is just short hand for, e.g.,

  (defmethod some-property ((instance bar))
     (slot-value instance 'slot-b))


And if you want to also have a constructor function, you don't even need
a macro.

  (defun make-bar (a b)
    (make-instance 'bar :a a :some-property))
    

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: Methods or class allocated slots
Date: 
Message-ID: <5r66p4F12fkebU1@mid.individual.net>
Thomas A. Russ wrote:

> For information that would be read-only class slots it doesn't make much
> difference if you implement them with a class slot or a method.  The
> only place it makes a difference is if you want to be able to change the
> value.  In that case class slots clearly make more sense.
> 
> If you want the value to be (potentially) different for each instance,
> then using regular slots is the simplest solution.

There is actually a good case for using methods instead of slots in 
conjunction with ContextL. ContextL allows you to associated methods 
with layers, and so it also allows you to associate (context-dependent) 
properties with classes and objects.

For example:

(define-layered-class iPhone () ())

(define-layered-function price (phone)
   (:method ((phone iPhone)) '(399 euro)))

(deflayer unlocked)

(defvar *german-iPhone* (make-instance 'iPhone))

(define-layered-method price :in-layer unlocked
   ((phone (eql *german-iPhone*)))
   '(999 euro))

(defvar *french-iPhone* (make-instance 'iPhone))

(define-layered-method price :in-layer unlocked
   ((phone (eql *french-iPhone*)))
   '(699 euro))

 > (price *german-iPhone*)
(399 EURO)

 > (with-active-layers (unlocked)
     (price *german-iPhone*))
(999 EURO)


Maybe ContextL lacks some language design to make something similar work 
for slots, but this variation works pretty well so far...


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/