Subject: bug#78162: [PATCH] hash-table-contains-p: Avoid creating a symbol on every call

From: Stefan Monnier <[email-masked]>
Date: Sun, 11 May 2025 01:31:31 -0400

> In any case, IMHO, it's not the magic value that's the problem here,
> it's that it's stored as a global symbol's value and thus becomes
> reachable via the obarray.

Then an alternative would be the simpler patch below?

> Stefan, any comments to the patch?

At this point we're firmly in bikeshed territory.

I agree with Daniel that the function should not allocate, but I also
agree with Pip Cet that the performance of the function shouldn't matter
very much, so maybe my ELisp version provides a middle ground?

[ Ideally, this function would be replaced with one which doesn't return
  just `t` but an actual "handle" on the hash-table slot, so that we can
  then access that slot without redoing the key lookup.  It would allow
  doing thing like `push` or `incf` on a hash-table entry without
  looking up the key twice.
  But doing so without allocating an object is hard with the current
  hash-table design (and would come with its own downsides).  ]

        Stefan

diff --git a/lisp/subr.el b/lisp/subr.el
index 79288921bed..962ae61cfd8 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -7436,11 +7436,11 @@
   (declare (important-return-value t))
   (string-trim-left (string-trim-right string trim-right) trim-left))
 
-(defsubst hash-table-contains-p (key table)
+(let ((missing (make-symbol "missing")))
+  (defsubst hash-table-contains-p (key table)
   "Return non-nil if TABLE has an element with KEY."
   (declare (side-effect-free t)
            (important-return-value t))
-  (let ((missing (make-symbol "missing")))
     (not (eq (gethash key table missing) missing))))
 
 ;; The initial anchoring is for better performance in searching matches.