This question already has an answer here:
-
Why does this function return a different value every time?
4 answers
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?
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
- Why does this function return a different value every time?
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:
- How could I explain this unexpected behavior of my Scheme code?
- Difference between '(()) and (cons null null)