The following is a very simple function called my-function
which begins by
setting the global variable L
to be the list containing nil
. The next
step is to modify (car L)
, a.k.a. nil
, by pushing foo
into it. The value
of (car L)
is then returned.
Since (car L)
started out being nil
, one expects it to become the
list (foo)
and in fact it does, but only upon the first call. The second time one calls my-function
a very unexpected behavior occurs in the sense that the
return value is (foo foo)
.
(defun my-function ()
(setq L '(nil)) ;; L is set to be a list containing a single element, namely the empty list
(push 'foo (car L)) ;; Push 'foo into (car L), which so far used to be nil. (car L) should therefore become the list (foo)
(car L)) ;; Return (car L)
(my-function) ;; Call my-function once
⇒ (foo) ;; As expected
(my-function) ;; Call my-function twice
⇒ (foo foo) ;; WHAT ???????
Why on earth do we get TWO foo's? my-function
started out destroying whatever previous value L
might have had, so the second call to my-function should return
the same thing as the first one!!!
Should one call my-function
successively, we get longer and longer lists of foo
's.
This is a minimalist version of a problem I encountered elsewhere and I'd really like to understand the reason for the behavior described above. Among other things I'd like to increase my understanding of the rules of scope in elisp, which I suspect is what is presently eluding me.
In particular I am not interested in workarounds, which I can easily
provide, such as replacing the line (setq L '(nil))
by (setq L (list nil))
(which actually also puzzles me a lot!).
EDIT: Some users suggested the related question Why does a constant in `let` change with repeated calls?
which is indeed pretty similar but the reliance there on the let
construct perhaps obscures the real reason behind the phenomenon which, as pointed out by @phils
and @shynur, is an attempt to change the value of a constant.
[...]
. I wonder if there is any reason why lisp should not prohibit modification of such constants once and for all, the same way(setq nil 1)
is prohibited. – Ruy Nov 27 '23 at 18:16