Search code examples
scopelispelisp

Understanding variable scope in given code


I'm a beginner in Emacs lisp, so this is really a noob question. Let's say that I have to write a function that uses a loop to add 1 to each element of a numeric vector.

Here is the code I wrote (the comments indicate what I'm trying to do at each step):

(defun add-one (x)
  "Use a loop to add 1 to each element of list X"
  (let* ((res x) ; make a copy of X
         (counter 0)) ; set counter to 0
    (while (< counter (length x))
      ;; Replace each element of RES by adding 1:
      (setcar (nthcdr counter res) (1+ (car (nthcdr counter x))))
      (setq counter (1+ counter)))
    ;; Display result:
    (message "%s" res)))

But my code seems to be destructive for x, since several calls to the function do not produce the same result:

;; Define a list:
(setq mylist '(1 2 3 4))
;; Several calls to the function:
(add-one mylist) ; -> (2 3 4 5)
(add-one mylist) ; -> (3 4 5 6)

Here is my question: I don't understand why my code is destructive (I expected the result to be (2 3 4 5) at each execution). I know that setcar is destructive, but it is applied to a copy of x, not to x itself. So why is the result changing?

Thanks!


Solution

  • Let does not make a copy of anything, so this assigns the value referenced by the variable x to the variable res. Hence any changes to the list referenced by res also change the list referenced by x

    (let* ((res x) ; make a copy of X