Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs Lisp: #s does not create a new hash table each time

Tags:

emacs

elisp

I have the following function:

(defun inc-map ()
  (let ((ht #s(hash-table test contents-hash))) 
    (dolist (i (list 1 2 3 4))
      (let ((old-val (or (gethash "foo" ht)
             0)))
    (puthash "foo" (+ 1 old-val) ht)))
    ht))

Despite the fact that this function seems to define the ht symbol locally, the function doesn't seem to be referentially transparent. In particular, calling it once returns the hash table "foo" -> 4, calling it a second time returns "foo" -> 8, a third time returns "foo" -> 12 and so on.

What exactly is going on here and how do I change this function to be referentially transparent (and return "foo" -> 4 every time)?

like image 729
lsankar4033 Avatar asked May 01 '16 08:05

lsankar4033


1 Answers

This might be considered a (slight) documentation bug, in that it suggests a little too firmly that using the printed representation creates a new hash table -- a statement which is open to misinterpretation.

However, you'll note that the documentation says that it's the elisp reader that recognises the printed representation of a hash table.

Therefore using #s is not the same as calling make-hash-table. The difference here is equivalent to the difference between quoting a list '(1 2 3) and calling (list 1 2 3).

The former in each case is processed by the reader and hence the same, single resulting object (hash table or list respectively) is seen during each evaluation.

Conversely, in the latter instances the reader is generating code which, when evaluated, will create a new hash table or list; and therefore you see a new object during each evaluation.

like image 159
phils Avatar answered Oct 21 '22 13:10

phils