GNU bug report logs -
#79706
31.0.50; problems with let-alist
Previous Next
To reply to this bug, email your comments to 79706 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79706; Package
emacs.
(Mon, 27 Oct 2025 10:53:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Eshel Yaron <me <at> eshelyaron.com>:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org.
(Mon, 27 Oct 2025 10:53:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Hi,
The implementation of let-alist currently suffers from some drawbacks:
1. It can create bindings for unused alist keys (false positives).
2. It can fail to create bindings for some alist keys (false negatives).
3. It generates inefficient code.
4. It's limited to read-only access.
A false positive (1) example:
(let-alist alist '.foo)
This form expands to:
(let ((alist alist))
(let ((.foo (cdr (assq 'foo enlist))))
'.foo))
Note how the local variable .foo is unused and the lookup is unneeded.
Likewise here:
(let-alist alist [.foo])
And also in these:
(let-alist alist (let ((.foo 'bar)) 'baz))
(let-alist alist (ignore-error .foo 'bar))
(let-alist alist (funcall #'.foo))
Here's another, slightly more "interesting" false positive:
(defalias 'la 'let-alist)
(let-alist alist (la blist .foo))
Now, a false negative (2) example:
(cl-macrolet ((oof () '.foo)) (let-alist alist (oof)))
This expands to:
(let ((alist alist)) (let nil .foo))
Which gives a void-variable error, because let-alist failed to generate
a binding for '.foo'.
Next, let's consider the common case in which an alist entry is
consulted only conditionally. A trivial example:
(let-alist alist (when nil .foo))
This expands to:
(let ((alist alist))
(let ((.foo (cdr (assq 'foo alist))))
(when nil .foo)))
In words: the generated code looks up 'foo' too early (3).
This is perhaps the most pressing issue since it affects existing code
"in the wild", even among the very few let-alist forms in core Emacs,
for example see align--rule-should-run and ffap-gopher-at-point.
Lastly, a missing feature, let-alist doesn't allow us to modify the
alist entries (4):
(let ((res nil))
(let-alist res (setf .foo 'bar))
res)
=> nil
These problems essentially stem from a common cause: the way let-alist
analyzes its body is too naive. It treats the body as plain data,
disregarding the actual semantics of ELisp code.
I suggest to either reimplement let-alist using a more sophisticated
code-walker (we might even be able to reuse elisp-scope.el for that!),
or deprecate it and perhaps provide an alternative based on local macros.
Thanks,
Eshel
This bug report was last modified 9 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.