Is this an implementation-specific behavior for literal cons?

144 Views Asked by At

I'm testing out the code in this interesting answer.

CL-USER> (defun literal-cons ()
        (let ((cons '(1 . 2)))
          (incf (cdr cons))
          cons))
; in: DEFUN LITERAL-CONS
;     (INCF (CDR CONS))
; --> LET* 
; ==>
;   (SB-KERNEL:%RPLACD #:CONS1 #:NEW0)
; 
; caught WARNING:
;   Destructive function SB-KERNEL:%RPLACD 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
LITERAL-CONS
CL-USER> (literal-cons)
(1 . 3)
CL-USER> (literal-cons)
(1 . 3)
CL-USER> (literal-cons)
(1 . 3)

As the behavior is not the same, I am wondering if SBCL has used the mentioned warning to change the behavior to something it thinks is more likely expected from the user? Expected:

TEST> (defun literal-cons ()
        (let ((cons '(1 . 2)))
          (incf (cdr cons))
          cons))
LITERAL-CONS
TEST> (literal-cons)
(1 . 3)
TEST> (literal-cons)
(1 . 4)
TEST> (literal-cons)
(1 . 5)
2

There are 2 best solutions below

0
Joshua Taylor On BEST ANSWER

The short answer is that yes, this is implementation specific behavior. As discussed in Unexpected persistence of data,

The relevant text from the HyperSpec on quote is:

The consequences are undefined if literal objects (including quoted objects) are destructively modified.

This means that any behavior you see from such a function is implementation specific (even if certain behaviors are more common among implementations than others).

0
monoid On

You should use:

(let ((cons (cons 1 2)))
   (defun nonliteral-cons ()
       (incf (cdr cons))
       cons))