Here is my answer to the identical question, appropriately edited:
The Bad
foo
is self-modifying code. This is extremely dangerous. While the variable lst
disappears at the end of the let
form, its initial value persists in the function object, and that is the value you are modifying. Remember that in Lisp a function is a first class object, which can be passed around (just like a number or a list), and, sometimes, modified. This is exactly what you are doing here: the initial value for lst
is a part of the function object and you are modifying it.
Let us actually see what is happening:
(symbol-function 'foo)
==> (lambda (e) (let ((lst (quote (a b c)))) (delq e lst)))
(foo 'c)
==> (a b)
(symbol-function 'foo)
==> (lambda (e) (let ((lst (quote (a b)))) (delq e lst)))
(foo 'b)
==> (a)
(symbol-function 'foo)
==> (lambda (e) (let ((lst (quote (a)))) (delq e lst)))
(foo 'a)
==> nil
(symbol-function 'foo)
==> (lambda (e) (let ((lst (quote (a)))) (delq e lst)))
The Good
In bar
, lst
is initialized to a fresh cons cell and thus is safe.
bar
does not modify its code.
The Bottom Line
In general, it is best to treat quoted data like '(1)
as constants - do not modify them:
quote
returns the argument, without evaluating it. (quote x)
yields x
.
Warning: quote
does not construct its return value, but just returns
the value that was pre-constructed by the Lisp reader (see info node
Printed Representation). This means that (a . b)
is not
identical to (cons 'a 'b)
: the former does not cons. Quoting should
be reserved for constants that will never be modified by side-effects,
unless you like self-modifying code. See the common pitfall in info
node Rearrangement for an example of unexpected results when
a quoted object is modified.
If you need to modify a list, create it with list
or cons
or copy-list
instead of quote
, like you do in bar
.
See more examples.
ps - variable naming
Emacs Lisp is a lisp-2 so these is no reason to name your variable lst
instead of list
.
C-h f quote
): "Warning:quote
does not construct its return value, but just returns the value that was pre-constructed by the Lisp reader". I think that newcomers to lisp are frequently oblivious to the whole concept of the lisp reader, and so taking some time to learn and understand the distinction between the "read" and "eval" stages is very beneficial to understanding the language in general, as well as specific issues like the one above.'
is a reader macro, which is processed in "read" stage, while(list 'a 'b 'c)
is evaluated in the "eval" stage?'
isn't a reader macro in elisp (elisp doesn't have reader macros), but it certainly is processed during the read phase. That's not the important thing, though. My point was about understanding that the reader transforms all of the textual lisp code into lisp objects (once), and it is those objects that are subsequently eval'd (often repeatedly), rather than the text that you see.