Can someone explain the following behavior? Specifically, why does the function return a different list every time? Why isn't some-list
initialized to '(0 0 0)
every time the function is called?
(defun foo ()
(let ((some-list '(0 0 0)))
(incf (car some-list))
some-list))
Output:
> (foo)
(1 0 0)
> (foo)
(2 0 0)
> (foo)
(3 0 0)
> (foo)
(4 0 0)
Thanks!
EDIT:
Also, what is the recommended way of implementing this function, assuming I want the function to output '(1 0 0)
every time?
Wanted to write one myself, but I found a good one online:
Ref http://c2.com/cgi/wiki?CommonLisp
'(0 0 0)
is a literal object, which is assumed to be a constant (albeit not protected from modification). So you're effectively modifying the same object every time. To create different objects at each function call use(list 0 0 0)
.So unless you know, what you're doing, you should always use literal lists (like
'(0 0 0)
) only as constants.'(0 0 0)
in code is literal data. Modifying this data has undefined behavior. Common Lisp implementations may not detect it at runtime (unless data is for example placed in some read-only memory space). But it can have undesirable effects.you see that this data may be (and often is) shared across various invocations of the same function
one of the more subtle possible errors is this: Common Lisp has been defined with various optimizations which can be done by a compiler in mind. For example a compiler is allowed to reuse data:
Example:
In above code snippet the compiler may detect that the literal data of
a
andb
isEQUAL
. It may then have both variables point to the same literal data. Modifying it may work, but the change is visible froma
andb
.Summary: Modification of literal data is a source of several subtle bugs. Avoid it if possible. Then you need to cons new data objects. Consing in general means the allocation of fresh, new data structures at runtime.
On a side note, defining this function in the sbcl REPL you get the following warning:
Which gives a good hint towards the problem at hand.