Studying hash tables in elisp, I tried to write a simple example:
(setq animals (make-hash-table))
(puthash "tiger" 120 animals)
(gethash "tiger" animals)
When I execute them line by line, call to gethash
returns nil
, despite the fact, that when I evaluate animals symbol, emacs prints this:
#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold
0.8 data ("tiger" 120 ...))
So, "tiger" is there, but gethash doesn't return it for some reason.
What's wrong?
docs for hash table functions
The default test for a hash table is eql
. Each time you type the string, you're creating a different string, so they're not eql
to each other.
(eql "tiger" "tiger") => nil
You need to use equal
as the test:
(setq animals (make-hash-table :test 'equal))
Or use symbols instead of strings as the keys in your table; since symbols are interned, typing the same symbol name twice results in the eql
objects.
The thing is that when Emacs prints the hash table and you can see "tiger"
in there, it's only showing you the printed representation of the real lisp objects in that structure, and printed representations can be ambiguous.
The printed representation of a string object is its value, so two string objects with the same value have the same printed representation and hence, once printed, it's impossible to distinguish them.
You're seeing the printed representation of the "tiger" string object you added to the table, but that's not the same string object that you queried it with in the next line.
The lisp reader creates these objects when it reads the code, and each time it reads a string it creates a new string object. As Barmar points out, symbols behave differently because they are interned by the lisp reader, so that it always 'reads' the same object. The situation with strings is similar to that with uninterned symbols -- you may find this related discussion useful.
It follows, of course, that lisp has many different forms of equality. You should familiarise yourself with at least eq
, eql
, equal
, =
, and string-equal
(alias string=
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With