From: Christophe Rhodes
Subject: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <sqd5hrclb2.fsf@cam.ac.uk>
CLOS has classes, class-names and (eql ,object) as valid method
specializers, which in the MOP translate to class objects and
eql-specializer objects.  PCL (the Xerox Parc implementation of CLOS,
not the book...) has vestigial support for (at least) two other forms
of specializers.

The first, CLASS-EQ, is relatively easy to understand; a method with
this specializer is applicable if the corresponding argument's class
is EQ to the specializer's class (rather than being a generalized
instance of that class).  The only question I have about this is
whether anyone can think of good uses for this; it seems to allow
violations of the normal views of inheritance, and break the ability
to extend behaviour, but maybe this is a useful thing in some
situations?

The second, PROTOTYPE, is much more mysterious to me; the code in PCL
is unfinished[*], and I couldn't find any references to what it was
intended to do.  Any ideas?  Was anyone who reads comp.lang.lisp now
there at the time?

Christophe

[*]
(defun saut-prototype (specl type)
  (declare (ignore specl type))
  (values nil nil)) ; fix this someday

From: Pascal Costanza
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <45c402F5vgu9U1@individual.net>
Christophe Rhodes wrote:
> CLOS has classes, class-names and (eql ,object) as valid method
> specializers, which in the MOP translate to class objects and
> eql-specializer objects.  PCL (the Xerox Parc implementation of CLOS,
> not the book...) has vestigial support for (at least) two other forms
> of specializers.
> 
> The first, CLASS-EQ, is relatively easy to understand; a method with
> this specializer is applicable if the corresponding argument's class
> is EQ to the specializer's class (rather than being a generalized
> instance of that class).  The only question I have about this is
> whether anyone can think of good uses for this; it seems to allow
> violations of the normal views of inheritance, and break the ability
> to extend behaviour, but maybe this is a useful thing in some
> situations?

It could make sense in conjunction with validate-superclass. The typical 
idiom

(defmethod validate-superclass
    ((class my-metaclass)
     (superclass standard-class))
   t)

is too liberal because now all subclasses of my-metaclass will 
automatically also be compatible with standard-class. A class-eq 
specializer could avoid this problem. (But I think that 
validate-superclass is misdesigned anyway...)



Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Tayssir John Gabbour
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <1140632842.652773.136170@f14g2000cwb.googlegroups.com>
Pascal Costanza wrote:
> (But I think that validate-superclass is misdesigned anyway...)

Could you expand on this a bit? I've looked around, and I haven't seen
this critique before.

Thanks,
Tayssir



Pascal Costanza wrote:
> Christophe Rhodes wrote:
> > CLOS has classes, class-names and (eql ,object) as valid method
> > specializers, which in the MOP translate to class objects and
> > eql-specializer objects.  PCL (the Xerox Parc implementation of CLOS,
> > not the book...) has vestigial support for (at least) two other forms
> > of specializers.
> >
> > The first, CLASS-EQ, is relatively easy to understand; a method with
> > this specializer is applicable if the corresponding argument's class
> > is EQ to the specializer's class (rather than being a generalized
> > instance of that class).  The only question I have about this is
> > whether anyone can think of good uses for this; it seems to allow
> > violations of the normal views of inheritance, and break the ability
> > to extend behaviour, but maybe this is a useful thing in some
> > situations?
>
> It could make sense in conjunction with validate-superclass. The typical
> idiom
>
> (defmethod validate-superclass
>     ((class my-metaclass)
>      (superclass standard-class))
>    t)
>
> is too liberal because now all subclasses of my-metaclass will
> automatically also be compatible with standard-class. A class-eq
> specializer could avoid this problem.
> (But I think that validate-superclass is misdesigned anyway...)
From: Pascal Costanza
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <466m96F9h6csU1@individual.net>
Tayssir John Gabbour wrote:
> Pascal Costanza wrote:
> 
>>(But I think that validate-superclass is misdesigned anyway...)
> 
> Could you expand on this a bit? I've looked around, and I haven't seen
> this critique before.

It's indeed the case that metaclasses are not necessarily compatible to 
each other. For example, one metaclass database-class can specialize 
slot access to store information in a database, and another metaclass 
authentication-class can specialize it to ensure that only authenticated 
users can read certain slots. These two metaclasses are not compatible 
because it is not clear whether the slot values stored in a database are 
as safe as they are in the authentication-class.

Now assume the implementor of database-class has written the following 
method on validate-superclass to ensure that standard-object can be used 
as a superclass.

(defmethod validate-superclass
   ((class database-class) (superclass standard-class))
   t)

This seems quite straightforward, object-oriented, etc. But what this 
definition actually does is, it declares all subclasses of 
standard-class to be acceptable superclasses for a database-class. (Read 
this until you get the base- and meta-levels right. ;)

So with this definition database-class and authentication-class would be 
accidentally compatible.

Next try. Let's implement validate-superclass as follows:

(defmethod validate-superclass
   ((class database-class)
    (superclass (eql (find-class 'standard-object))))
   t)

OK, this solves the problem for the implementor - because 
standard-object is always the default superclass, so at least that class 
must be an acceptable superclass. But now the user cannot really use 
database-class as freely as necessary. The problem was accidental 
compatibility with subclasses of standard-class, not with direct 
instances of standard-class themselves. So next attempt:

(defmethod validate-superclass
   ((class database-class) (superclass standard-class))
   (eq (class-of superclass) (find-class 'standard-class)))

I am not 100% sure that this is correct, but I am quite sure that this 
gets too complicated.

I think in most practical cases, metaclass compatibility is not a real 
issue, and having to implement methods for validate-superclass is just 
annoying. I would rather prefer a phrase like "the consequences are 
undefined when incompatible metaclasses are used in conjunction", or 
some such.

See also 
http://groups.google.com/group/comp.lang.clos/msg/83cc9759229d2fd0 and 
http://groups.google.com/group/comp.lang.clos/msg/ddde03d83c7e8f0b


Pascal

-- 
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
From: Kaz Kylheku
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <1139901810.622788.127440@f14g2000cwb.googlegroups.com>
Christophe Rhodes wrote:
> The first, CLASS-EQ, is relatively easy to understand; a method with
> this specializer is applicable if the corresponding argument's class
> is EQ to the specializer's class (rather than being a generalized
> instance of that class).  The only question I have about this is
> whether anyone can think of good uses for this; it seems to allow
> violations of the normal views of inheritance, and break the ability
> to extend behaviour, but maybe this is a useful thing in some
> situations?

It could sure be useful to have an exact class match. Sometimes there
are methods which just don't make sense for anything other than a
specific type, not even subtypes.

Hmm, how about some example:

;;;
;;; Given an encryption key, this method creates an encryption context
;;; object or "encryptor". The two have to be of matching classes,
which
;;; generally follow a parallel inheritance.
;;;
(defmethod make-encryptor ((obj (class-eq des-encryption-key)))
  (make-instance 'des-encryptor))

Or:

;;;
;;; Convert object to string.
;;;
(defmethod tostring ((obj (class-eq foo)))
  ;; logic specific to class FOO
  )

This prevents the pitfall of someone creating a derived class BAR from
FOO, but neglecting to implement TOSTRING, which will fail to render
any slots specific to BAR only! When you are using regular
specializations on class, you are writing a method not only over the
classs you are naming in that combination, but potentially over all
possible derived combinations. Sometimes that's could just be too much
responsibility. :)
From: Matthew D Swank
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <pan.2006.02.14.13.39.12.879360@c.net>
On Mon, 13 Feb 2006 15:47:45 +0000, Christophe Rhodes wrote:

> The second, PROTOTYPE, is much more mysterious to me; the code in PCL
> is unfinished[*], and I couldn't find any references to what it was
> intended to do.  Any ideas?  Was anyone who reads comp.lang.lisp now
> there at the time?
> 
> 
> [*]
> (defun saut-prototype (specl type)
>   (declare (ignore specl type))
>   (values nil nil)) ; fix this someday

From http://www.isr.ist.utl.pt/library/docs/encycmuclopedia/doc/impl/pcl/5-22-87-notes.text


    the defclass and class-definition protocol has changed.  some of the
  effects of this change are:

  * ADD-NAMED-CLASS is a true functional interface for defclass, so for
    example,

    (defclass foo () (x y z) (:accessor-prefix foo-))

    is equivalent to:

    (add-named-class (class-prototype (class-named 'class))
                     'foo
                     ()
                     '(x y z)
                     '((:accessor-prefix foo-)))


Is it related to this iteration of PCL?


Matt
-- 
"You do not really understand something unless you can
 explain it to your grandmother." — Albert Einstein.
From: Christophe Rhodes
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <sqpslq6nkf.fsf@cam.ac.uk>
Matthew D Swank <·······································@c.net> writes:

> From http://www.isr.ist.utl.pt/library/docs/encycmuclopedia/doc/impl/pcl/5-22-87-notes.text
>
>
>     the defclass and class-definition protocol has changed.  some of the
>   effects of this change are:
>
>   * ADD-NAMED-CLASS is a true functional interface for defclass, so for
>     example,
>
>     (defclass foo () (x y z) (:accessor-prefix foo-))
>
>     is equivalent to:
>
>     (add-named-class (class-prototype (class-named 'class))
>                      'foo
>                      ()
>                      '(x y z)
>                      '((:accessor-prefix foo-)))
>
>
> Is it related to this iteration of PCL?

I don't think so; I think that the MOP function CLASS-PROTOTYPE is
mostly unrelated to this PROTOTYPE specializer.  At the very least,
this notes file is insufficient to divine the intended function of the
specializer, even if it is relevant.

Christophe
From: Ivan Boldyrev
Subject: Re: CLOS specializers and Portable Common Loops
Date: 
Message-ID: <1k53d3-ku3.ln1@ibhome.cgitftp.uiggm.nsc.ru>
On 9384 day of my life Christophe Rhodes wrote:
> The first, CLASS-EQ, is relatively easy to understand; a method with
> this specializer is applicable if the corresponding argument's class
> is EQ to the specializer's class (rather than being a generalized
> instance of that class).  The only question I have about this is
> whether anyone can think of good uses for this...

Something like MY-EQUAL generic function if you wish only objects of
EQ classess to be comparable.

Though there is a workaround:

(defgeneric my-equal (a b)
  (:method-combination and))

(defmethod my-equal :around (a b)
  (and (eq (class-of a) (class-of b))
       (call-next-method)))

(defclass fruit ()
  ((title :initarg :title)))

(defmethod my-equal and ((a fruit) (b fruit))
  (equal (slot-value a 'title)
         (slot-value b 'title)))

(defclass apple (fruit)
  ())

(defclass orange (fruit)
  ())

(let ((a1 (make-instance 'apple :title "Golden"))
      (a2 (make-instance 'apple :title "Golden"))
      (o1 (make-instance 'orange :title "Golden")))
  (list (my-equal a1 a2)
        (my-equal a1 o1)))
; => (T NIL)

-- 
Ivan Boldyrev

       Assembly of a Japanese bicycle requires greatest peace of spirit.