I have a list of seven integers, initially all 0s, let's call it "data." Periodically during the course of running my program I want to increment the value of one of those integers by one. At the end of the program I print data. All is fine, except that on each successive run of the program all the values of data from the last run are added to all the values of data from this run. I want only the values of data from this run. This unexpected behavior occurs whether data is a local variable within a class's method, a local variable within a separate function called by a class's method, or a slot of a class. It happens whether I increment the individual values of data by incf or (setf value (1+ value)). When I reload the program, data resets to all zeroes but when I run the program again data again adds all of the last run's data to this run's data. When I increment one of the values of data I use the function nth with index being the value of another object's slot. What could cause this unwelcome persistence of values of my "data" list?
-
Please add some code to this question. We'll need to see how the data is stored, specifically, in order to answer this. You mention “"data" list”, and I wouldn't be surprised if you're modifying a quoted list somewhere. – Joshua Taylor Sep 13 '13 at 15:51
-
I was using a quoted list, as you suspected. When I changed that to the function, list, the unexpected behavior ceased. – fpt Sep 13 '13 at 16:33
1 Answers
Are you doing something like this:
CL-USER> (defun foo ()
(let ((value '(1))) ; '(1) is literal data
(incf (car value))))
FOO
CL-USER> (foo)
2
CL-USER> (foo)
3
CL-USER> (foo)
4
CL-USER> (foo)
5
Quoted data is literal data; there's only one copy of it, and the consequences of modifying it are undefined. The behavior above is common, but you can't depend on it. Some compilers will give a warning when you do this. E.g., in SBCL:
CL-USER> (defun foo ()
(let ((value '(1)))
(incf (car value))))
; in: DEFUN FOO
; (INCF (CAR VALUE))
; --> LET*
; ==>
; (SB-KERNEL:%RPLACA #:TMP1 #:NEW0)
;
; caught WARNING:
; Destructive function SB-KERNEL:%RPLACA called on constant data.
; See also:
; The ANSI Standard, Special Operator QUOTE
; The ANSI Standard, Section 3.2.2.3
;
; compilation unit finished
; caught 1 WARNING condition
FOO
The relevant text from the HyperSpec on quote
is:
The consequences are undefined if literal objects (including quoted objects) are destructively modified.
Create modifiable lists with, e.g., (list 1)
, not '(1)
. This is a common pitfall until you've encountered it. There are some other questions on StackOverflow that mention this issue. A very specific one is
but there are a bunch, too:
- LISP: Why doesn't mapcan accept my list give as parameters? (an interesting case with a literal list inside a lambda function passed to mapcan)
- Unexpected List Duplication using Sort with Common Lisp
- LISP - Global variable keep their old value after reinitialization
- this answer to Sudoku table generator failure, lisp
- How does Lisp function remember state in this code?
- Do property lists in Common Lisp refer to some global state?
- Why does this function return a different value every time?
- Strange behavior invoking destructive Common LISP function receiving as argument a list created with quote
- Local variable keeps data from previous execution
- What is happening with this Common Lisp code?
- Unexpected persistence of data (this question)
- setf in a function does not work
- duplicating and modifying the head of a list of list, in Lisp
The same thing happens in Scheme, though the citations to the documentation are obviously different. For R5RS, the documentation is the following:
4.1.2 Literal expressions
… As noted in section 3.4, it is an error to alter a constant (i.e. the value of a literal expression) using a mutation procedure like set-car! or string-set!.
3.4 Storage model
… In many systems it is desirable for constants (i.e. the values of literal expressions) to reside in read-only-memory. To express this, it is convenient to imagine that every object that denotes locations is associated with a flag telling whether that object is mutable or immutable. In such systems literal constants and the strings returned by symbol->string are immutable objects, while all objects created by the other procedures listed in this report are mutable. It is an error to attempt to store a new value into a location that is denoted by an immutable object.
There are questions about this as well:

- 6,955
- 6
- 40
- 55

- 84,998
- 9
- 154
- 353
-
Another question, if I define a function in SBCL as: `(defun set-head (x v) (rplaca x v))`, then why this expression `(let ((x '(a b))) (set-head x 'z))` do not raise a warning? I test it on SBCL 1.2.7. – xiepan May 29 '15 at 05:28
-
@xiepan There's no *requirement* that a warning be issued. The behavior is still undefined. And even in implementations that do warn in some cases, I don't see any guarantee that they do so in all situations. Was your code in a file that you compiled? Or something you typed in at the REPL? You could write to the SBCL mailing list and ask about this specific case. – Joshua Taylor May 29 '15 at 12:14