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/
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/
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. :)
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
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.