Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

gethash doesn't work for string keys

Tags:

emacs

elisp

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

like image 666
user4035 Avatar asked Sep 02 '25 02:09

user4035


2 Answers

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.

like image 111
Barmar Avatar answered Sep 05 '25 01:09

Barmar


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=).

like image 22
phils Avatar answered Sep 05 '25 00:09

phils