From: Simon Katz
Subject: Something like EQUALP that descends instances
Date: 
Message-ID: <376bb6fe@newsread3.dircon.co.uk>
I want a function similar to EQUALP, but which descends CLOS instances
in the same way that EQUALP descends structures.

Is there a way to do this without writing code to deal with all the
cases that EQUALP already deals with?
______________________________
Simon Katz

From: Kent M Pitman
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <sfwemj8ymaq.fsf@world.std.com>
"Simon Katz" <·····@dircon.co.uk> writes:

> I want a function similar to EQUALP, but which descends CLOS instances

Just fyi, structures and numbers are CLOS instances.  CL uses the terminology
"standard objects" for what you are calling instances.  3 is an instance
but of a different metaclass (and, incidentally, one that the function
make-instance doesn't let you make).  CLOS is an explanatory theory of all
objects in CL, not just the so-called "instances" [of standard-class].

> in the same way that EQUALP descends structures.

I claim that This is not really semantically meaningful.  You cannot
descend an object without knowing the meaning of its parts and expect
to win other than heuristically.  Of course, maybe EQUALP itself is a
sham, you might say, but the point is that people eventually outgrow
it and I think that's a good thing.  Making it generic or making
something like it that is more able to allow people to continue using
it would only promote even worse modularity than there is now.

(defclass rectangle ()
  ((width  :initarg :width  :initform 0   :accessor width )
   (height :initarg :height :initform 0   :accessor height)
   (area                    :initform nil :accessor area-internal  )))

(defmethod area ((r rectangle)) 
  (or area
      (setq area (* (width r) (hieght r)))))

(defmethod (setf width) :after ((r rectangle))
  (setq area nil))

(defmethod (setf height) :after ((r rectangle))
  (setq area nil))

(setq a (make-instance 'rectangle :width 5 :height 4))
(setq b (make-instance 'rectangle :width 5 :height 4))
(area a)
(equalp a b) => nil

This is kind of a contrived example, but I hope it makes my point.

> Is there a way to do this without writing code to deal with all the
> cases that EQUALP already deals with?

I doubt it.  The problem is that EQUALP descends structs (which is already
ill-advised) and you can't write that yourself without the MOP.
(If you don't mind using the MOP, which is not part of the standard
but is widely available in commercial implementations, then it's trivial.
Your code probably won't then port to certain free implementations.)
If you want to compare something which is #S(FOO :SOMETHING #<my-obj>)
where #<my-obj> is a standard class, you can't give control over to EQUALP
and later get it back, and there is no other operator for getting down
into the structure of the FOO.  Personally, I don't think that's so bad.
I think you shouldn't be randomly violating others' abstractions without
permission/understanding.  I'm sure someone probably thinks that is
hopelessly mean, insensitive, unresponsive, or something like that of me.
So it goes. I mostly never got to appear cruel and hard-hearted while 
working for a vendor for fear it would sound like vendor policy.  It's
not vendor policy.  I'm sure all the vendors probably cry inside for
you.  But I guess I take (now not-so-) secret delight in seeing that you
have an  excellent opportunity like this to rethink your problem.

The real problem with EQUALP and others like it is that they work on
representational types, not intentional types.  See my paper
 http://world.std.com/~pitman/PS/EQAUL.html
if you haven't read my diatribe on this.
From: Tom Breton
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <m37loy8sar.fsf@world.std.com>
Kent M Pitman <······@world.std.com> writes:

> 
> (setq a (make-instance 'rectangle :width 5 :height 4))
> (setq b (make-instance 'rectangle :width 5 :height 4))
> (area a)
> (equalp a b) => nil
> 
> This is kind of a contrived example, but I hope it makes my point.

IMO it only makes part of your point.  One could still provide equalp
as a default, much as constructors and printers are, and let it be
overridden as required.

-- 
Tom Breton, http://world.std.com/~tob
Ugh-free Spelling (no "gh") http://world.std.com/~tob/ugh-free.html
From: Kent M Pitman
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <sfw7loy1n7o.fsf@world.std.com>
Tom Breton <···@world.std.com> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > 
> > (setq a (make-instance 'rectangle :width 5 :height 4))
> > (setq b (make-instance 'rectangle :width 5 :height 4))
> > (area a)
> > (equalp a b) => nil
> > 
> > This is kind of a contrived example, but I hope it makes my point.
> 
> IMO it only makes part of your point.  One could still provide equalp
> as a default, much as constructors and printers are, and let it be
> overridden as required.

EQUALP is a "universal" or "total" function [already defined over all
arguments].  What would it mean to override its behavior?  Consider:

 (let ((foo (make-instance 'foo :x 3)))
   (list (equalp x foo)
         (progn (defmethod equalp (thing (foo foo)) (eql thing (foo-x foo)))
	        (equalp x foo))))
 => (NIL T)

Not that I recommend code like this, but my point is that you are not
defining, but incompatibly REdefining the meaning of EQUALP were you 
to be able to add methods to it.

(I think it would also impact EQUALP hash tables in odd ways, but I've
not thought hard about it.)
From: Marco Antoniotti
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <lwiu8h1m2s.fsf@copernico.parades.rm.cnr.it>
Kent M Pitman <······@world.std.com> writes:

> "Simon Katz" <·····@dircon.co.uk> writes:
> 
> > I want a function similar to EQUALP, but which descends CLOS instances
> 
> (defclass rectangle ()
>   ((width  :initarg :width  :initform 0   :accessor width )
>    (height :initarg :height :initform 0   :accessor height)
>    (area                    :initform nil :accessor area-internal  )))
> 
> (defmethod area ((r rectangle)) 
>   (or area
>       (setq area (* (width r) (hieght r)))))

?!?  Am I missing something?  Is 'area' the method *and* the slot, or
just a global variable.

Cheers


-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Barry Margolin
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <Haxb3.776$KM3.206906@burlma1-snr2>
In article <··············@copernico.parades.rm.cnr.it>,
Marco Antoniotti  <·······@copernico.parades.rm.cnr.it> wrote:
>
>Kent M Pitman <······@world.std.com> writes:
>
>> "Simon Katz" <·····@dircon.co.uk> writes:
>> 
>> > I want a function similar to EQUALP, but which descends CLOS instances
>> 
>> (defclass rectangle ()
>>   ((width  :initarg :width  :initform 0   :accessor width )
>>    (height :initarg :height :initform 0   :accessor height)
>>    (area                    :initform nil :accessor area-internal  )))
>> 
>> (defmethod area ((r rectangle)) 
>>   (or area
>>       (setq area (* (width r) (hieght r)))))
>
>?!?  Am I missing something?  Is 'area' the method *and* the slot, or
>just a global variable.

It's the slot.  Kent forgot to wrap a WITH-ACCESSORS around the body of the
method.  It should be:

(defmethod area ((r rectangle))
  (with-accessors ((area area-internal)) r
    (or area
        (setq area (* (width r) (height r))))))

Thus, the AREA slot is used to cache the computed area.  The point of the
example was that two rectangles might be functionally equivalent (because
they have the same height and width), but an equivalence predicate that
looked at them structurally would distinguish them based merely on whether
the areas had been cached.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Marco Antoniotti
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <lwhfo19jyk.fsf@copernico.parades.rm.cnr.it>
Barry Margolin <······@bbnplanet.com> writes:

> In article <··············@copernico.parades.rm.cnr.it>,
> Marco Antoniotti  <·······@copernico.parades.rm.cnr.it> wrote:
> >
> >Kent M Pitman <······@world.std.com> writes:
> >
> >> "Simon Katz" <·····@dircon.co.uk> writes:
> >> 
> >> > I want a function similar to EQUALP, but which descends CLOS instances
> >> 
> >> (defclass rectangle ()
> >>   ((width  :initarg :width  :initform 0   :accessor width )
> >>    (height :initarg :height :initform 0   :accessor height)
> >>    (area                    :initform nil :accessor area-internal  )))
> >> 
> >> (defmethod area ((r rectangle)) 
> >>   (or area
> >>       (setq area (* (width r) (hieght r)))))
> >
> >?!?  Am I missing something?  Is 'area' the method *and* the slot, or
> >just a global variable.
> 
> It's the slot.  Kent forgot to wrap a WITH-ACCESSORS around the body of the
> method.  It should be:
> 
> (defmethod area ((r rectangle))
>   (with-accessors ((area area-internal)) r
>     (or area
>         (setq area (* (width r) (height r))))))
> 
> Thus, the AREA slot is used to cache the computed area.  The point of the
> example was that two rectangles might be functionally equivalent (because
> they have the same height and width), but an equivalence predicate that
> looked at them structurally would distinguish them based merely on whether
> the areas had been cached.
> 

Thought so.

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Kent M Pitman
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <sfwg13lxckq.fsf@world.std.com>
Marco Antoniotti <·······@copernico.parades.rm.cnr.it> writes:

> Kent M Pitman <······@world.std.com> writes:
> 
> > "Simon Katz" <·····@dircon.co.uk> writes:
> > 
> > > I want a function similar to EQUALP, but which descends CLOS instances
> > 
> > (defclass rectangle ()
> >   ((width  :initarg :width  :initform 0   :accessor width )
> >    (height :initarg :height :initform 0   :accessor height)
> >    (area                    :initform nil :accessor area-internal  )))
> > 
> > (defmethod area ((r rectangle)) 
> >   (or area
> >       (setq area (* (width r) (hieght r)))))
> 
> ?!?  Am I missing something?  Is 'area' the method *and* the slot, or
> just a global variable.

Meant to use with-slots or say (setf (area-internal r) ...).
Sorry about that.  Thanks for catching that.

Too many years writing Flavors code, I guess.
From: David Bakhash
Subject: Re: Something like EQUALP that descends instances
Date: 
Message-ID: <cxjogiculgj.fsf@acs5.bu.edu>
"Simon Katz" <·····@dircon.co.uk> writes:

> I want a function similar to EQUALP, but which descends CLOS instances
> in the same way that EQUALP descends structures.

I think this is something that you just have to work through.  I've
investigated things like this, and it seems like the family of EQUAL's
functions only go so far, and WRT CLOS, I don't think you'll find this, unless
someone's implemented it.  CLOS objects are much more complex than structs,
and so I don't think that such facilities would be general enough to be
justified in the language.  Plus, what about generic functions that are
different based on object attributes in the EQ sense (i.e. not the EQUAL
sense, such as print-object using print-unreadable-object with :identity t?).
It's a big mess, and so I'd go with KMP's suggestion to "write your own".

After giving it some thought, I'm glad the language doesn't have CLOS
equalp's.

dave