Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On hash tables, key insertion order matters, unlike equalp #5

Open
anticrisis opened this issue Sep 4, 2017 · 4 comments
Open

On hash tables, key insertion order matters, unlike equalp #5

anticrisis opened this issue Sep 4, 2017 · 4 comments

Comments

@anticrisis
Copy link

Unlike the equalp operator, the order in which keys are inserted seems to affect equals. Is this desired behavior or a bug?

CL-USER> (defvar a (make-hash-table))
A
CL-USER> (defvar b (make-hash-table))
B
CL-USER> (setf (gethash :a a) 1)
1
CL-USER> (setf (gethash :b a) 2)
2
CL-USER> (setf (gethash :b b) 2)
2
CL-USER> (setf (gethash :a b) 1)
1
CL-USER> (equalp a b)
T
CL-USER> (generic-comparability:equals a b)
NIL

This is on SBCL 1.3.21.

@pnathan
Copy link
Owner

pnathan commented Sep 4, 2017 via email

@anticrisis
Copy link
Author

Seems the problem is here:

(loop
for k1 in (hash-table-keys a)
for k2 in (hash-table-keys b)
always (apply
#'(lambda (a b)
(equals a b :recursive recursive))
k1 k2 keys))
t)

(hash-table-keys) will return keys in an unspecified order. I haven't looked at equalp, but I imagine a correct implementation would iterate through the keys of the first hash table and query the second hash table on those keys.

@pnathan
Copy link
Owner

pnathan commented Sep 4, 2017 via email

@anticrisis
Copy link
Author

In reading CDR-8, I think there's a conflict between its description of EQUALS for hash tables, and hash-tables's use of an equivalence test function. If by-key is T, CDR-8 overrules the hash table's test function for comparing keys.

For example, if the hash tables use EQUALP as their equivalence test, the keys "a" and "A" would be equivalent. But under EQUALS, "a" and "A" are not equivalent. Therefore, EQUALS would return NIL, but an iteration of every key and value in the first hash table, and a GETHASH test of those keys in the second table, would return T.

This inconsistency makes my proposed implementation incorrect, since it would rely on GETHASH to query the second hash table for the presence of each key in the first hash table. GETHASH, of course, cannot use EQUALS, because user-defined test hash table test functions are not part of the standard.

So it seems that if by-key is T, the only correct implementation of CDR-8 is to sort the keys in the first table (with COMPARE), and then check for their existence in the second table.

If by-key is NIL, I assume we should use the hash-table's equivalence test? CDR-8 is silent on this point.

The algorithm in CDR-8 seems incomplete, in that it neglects to confirm that both hash tables use the same equivalence test, unless check-properties is T. But if the hash tables don't use the same equivalence test, then isn't it meaningless to try to assert by-value equality?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants