Reputation: 189
I'm getting some strange behavior when I try to set a global parameter within a method.
(defparameter *global-var-1* nil)
(defun method1 ()
(setf *global-var-1* '())
(format t "~a~%" *global-var-1*)
...
(loop
...
(setf *global-var-1* '(a))
(format t "~a~%" *global-var-1*)
(nconc *global-var-1* (list '(b c))))
In the above code, when I call method1, the first format statement always prints nil
as expected. The second format statement prints (A)
the first time method1 is called, but the second time it prints (A (B C))
. The third time (A (B C) (B C))
and so on. Instead of setting *global-var-1*
to (A)
, setf seems to be setting it to the previous known value. What am I doing wrong? BTW, I was setting *global-var-1
to (A)
because nconc
won't work with an empty list. I remove (A)
later on before exiting method1.
Upvotes: 2
Views: 135
Reputation: 14291
Of course nconc
works with empty lists, but you must always assign its return value, like this:
CL-USER> (defparameter *x* nil)
*X*
CL-USER> (setq *x* (nconc *x* (list 'a)))
(A)
CL-USER> *x*
(A)
Then, your problem is solved by not using literal lists:
CL-USER> (defparameter *x* nil)
*X*
CL-USER> (defun foo ()
(setf *x* nil)
(dotimes (n 3)
(progn (setf *x* (list 'a))
(format t "~a~%" *x*)
(setf *x* (nconc *x* (list (list 'b 'c)))))))
FOO
CL-USER> (foo)
(A)
(A)
(A)
You should always be careful when using destructive operations, and be aware of the implications of using them with literal expressions. In your code, nconc
destructively modified the cdr
of your '(a)
list literal, which results in the behavior you observed. (You could always use append
to get around this, if you're not optimizing.)
You might also be interested in my other answer about this topic.
Upvotes: 6