...
but then I noticed that the language already provides a mechanism for
writing a perfect EQ hashing function:
(DEFVAR *EQ-HASH-TABLE* (MAKE-HASH-TABLE :TEST #'EQ))
(DEFVAR *EQ-HASH-COUNTER* 0)
(DEFUN EQHASH (X)
(OR (GETHASH X *EQ-HASH-TABLE*)
(SETF (GETHASH X *EQ-HASH-TABLE*) (INCF *EQ-HASH-COUNTER*))))
So I guess the point is that given magic EQ and EQL hashtables that work
even when a GC moves things, you can use these to build a slower version
of EQ and EQL hashtables (and related thingies) that also works, without
giving the users direct access to the magic. Interesting in principle,
but not the way you'd want to do anything real.
By allowing the user to specify at hashtable creation time whether his
hashing function at some level makes use of something that amounts to an
address pointer (and which will therefore need to be fixed after a
copying GC mangles things), we allow the user to win without having to
make hashtable references in the course of his comparison.
-- Scott