From: Lawrence Mandow
Subject: CLOS instances, equalp, and hash tables
Date: 
Message-ID: <f2iglg$gdf$1@mercurio.cica.es>
I am having some trouble using class instances as keys in hash tables. 
Basically, class instances are not equalp. This looks like a 
disadvantage of classes when compared to structures.

The following example works well with structures,

 >(setf *ht* (make-hash-table :test #'equalp))
#<EQUALP Hash Table{0} 2117DCCC>

 > (defstruct mys s1)
MYS

 > (equalp (make-mys :s1 1) (make-mys :s1 1))
T

 > (setf (gethash (make-mys :s1 1) *ht*) t)
T

 > (gethash (make-mys :s1 1) *ht*)
T
T

However, replacing the structure with a similar class will not yield the 
same desired behavior,

 > (defclass myc () ((s1 :initarg :s1 :reader s1)))
#<STANDARD-CLASS MYC 203FB3B4>

 > (equalp (make-instance 'myc :s1 1) (make-instance 'myc :s1 1))
NIL

 > (setf (gethash (make-instance 'myc :s1 1) *ht*) T)
T

 > (gethash (make-instance 'myc :s1 1) *ht*)
NIL
NIL

Is there an easy way to stick to CLOS and come around this problem?
I am using something like,

(defmethod key ((obj myc))
   (list (s1 obj)))   ;list all slots in the class

 >(setf (gethash (key (make-instance 'myc :s1 1)) ht) T)
T
 >(gethash (key (make-instance 'myc :s1 1)) ht)
T

but I find it quite cumbersome as a general solution.

Thanks,
Lawrence

From: Edi Weitz
Subject: Re: CLOS instances, equalp, and hash tables
Date: 
Message-ID: <u1wheipfn.fsf@agharta.de>
On Thu, 17 May 2007 23:15:18 +0200, Lawrence Mandow <········@lcc.uma.es> wrote:

> I am having some trouble using class instances as keys in hash
> tables. Basically, class instances are not equalp. This looks like a
> disadvantage of classes when compared to structures.

You might want to read this:

  http://www.nhplace.com/kent/PS/EQUAL.html

> Is there an easy way to stick to CLOS and come around this problem?

In your specific case (hash tables) you could use
implementation-specific behaviour like specifying your own hash tests.
For example in LispWorks:

  http://www.lispworks.com/documentation/lw50/LWRM/html/lwref-86.htm

HTH,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Richard M Kreuter
Subject: Re: CLOS instances, equalp, and hash tables
Date: 
Message-ID: <873b1u44bc.fsf@tan-ru.localdomain>
Lawrence Mandow <········@lcc.uma.es> writes:

> I am having some trouble using class instances as keys in hash
> tables. Basically, class instances are not equalp.

That's right.  In case you haven't read the entry for EQUALP, have a
look:

http://www.lisp.org/HyperSpec/Body/fun_equalp.html

> Is there an easy way to stick to CLOS and come around this problem?

Not in vanilla CLOS.  However, many implementations support the
MetaObject Protocol (MOP), which permits you to query the slots of a
class, e.g., if the MOP functions are in a package called MOP,
something like this might do:

  (mapcar #'mop:slot-definition-name (mop:class-slots (class-of instance)))

Using this with SLOT-BOUNDP, SLOT-VALUE and CLASS-OF, you can define
various keying functions.

> I am using something like,
>
> (defmethod key ((obj myc))
>   (list (s1 obj)))   ;list all slots in the class

In case this function does what you want, notice that it's quite a
different equivalence relation than EQUALP on structures: objects of
different types can be equivalent under this relation, in case they've
got the same slot values, and objects with different slot names but
equivalent slot values will key equivalently: for example, two
instances each with one slot whose values are both 1 will key to the
same list.

Hope that helps,
RmK