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

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

Although this function appears to define the ht symbol locally, the function does not appear to be referentially transparent. In particular, calling it once returns the hash table "foo" -> 4 , calling it a second time, returns "foo" -> 8 , the third time returns "foo" -> 12 , etc.

What exactly is happening here and how can I change this function as link-transparent (and return "foo" -> 4 every time)?

+5
source share
1 answer

This may be considered a documentation error (minor), because it suggests that using the printed representation creates a new hash table - an instruction that is open to misinterpretation.

However, you will notice that the documentation says that it is an elisp reader that recognizes the printed representation of the hash table.

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

The first in each case is processed by the reader and, therefore, the same single resultant object (hash table or list, respectively) is displayed during each assessment.

Conversely, in the latter cases, the reader generates code that, when evaluated, creates a new hash table or list; and therefore you see a new object during each assessment.

+5
source

All Articles