From: Christophe Rhodes
Subject: modification of constants
Date: 
Message-ID: <sq64u7gnyd.fsf@cam.ac.uk>
A perennial trap for the unwary and the inexperienced is modification
of literals: for example

  (defun foo (x)
    (let ((y (list #(1) #(2))))
      (format t "~S" y)
      (setf (aref (second y) 0) x)
      (format t "~S" y)))

similar to a query here a little while ago.  It's relatively easy to
understand that this attempts to modify the literal objects in the
program, and (in the CLHS under QUOTE) this is forbidden.

So far, so usual: this issue comes up moderately regularly here.  But
what about slightly more subtle cases?

  (let ((location (cons nil nil)))
    (funcall (compile nil '(lambda (x) (setf (cdr ',location) x))) 1)
    location)

I, at least, was surprised to learn that this code is formally
non-conforming -- and similarly that

  (let ((location (vector t)))
    (funcall (compile nil '(lambda () (setf (aref ,location 0) nil))))
    location)

gives undefined consequences by the spec.  Even

  (let ((location (cons nil nil)))
    (eval `',location)
    (setf (car location) t))

would seem to be formally undefined. 

I've read the ANSI issues QUOTE-SEMANTICS:NO-COPYING and
CONSTANT-MODIFICATION:DISALLOW, and an initial reading suggests that
this undefinedness wasn't strictly intended, since the action of QUOTE
in code passed to EVAL or COMPILE is to preserve the identity of the
object quoted; does anyone know whether this is in fact the case?

(It's possible to work around this kind of problem with either
load-time-value or a closure: e.g.
  (let ((location (cons nil nil)))
    (funcall (funcall (compile nil '(lambda (l) (lambda (x) (setf (cdr l) x))))
                      location)
             1))
but should I be surprised that this is necessary?)

Christophe

From: John
Subject: Re: modification of constants
Date: 
Message-ID: <slrndg1ibp.km3.VVVBPEfd@mailinator.com>
On 2005-08-15, Christophe Rhodes <·····@cam.ac.uk> wrote:
>  So far, so usual: this issue comes up moderately regularly here.  But
>  what about slightly more subtle cases?
> 
>    (let ((location (cons nil nil)))
>      (funcall (compile nil '(lambda (x) (setf (cdr ',location) x))) 1)
>      location)
> 
>  I, at least, was surprised to learn that this code is formally
>  non-conforming

Since when can you have a comma not inside a backquote?

> -- and similarly that
> 
>    (let ((location (vector t)))
>      (funcall (compile nil '(lambda () (setf (aref ,location 0) nil))))
>      location)
> 
>  gives undefined consequences by the spec.

Err, isn't this also an error... comma without a backquote?
From: Christophe Rhodes
Subject: Re: modification of constants
Date: 
Message-ID: <sq1x4vglk9.fsf@cam.ac.uk>
John <········@mailinator.com> writes:

> On 2005-08-15, Christophe Rhodes <·····@cam.ac.uk> wrote:
>>  So far, so usual: this issue comes up moderately regularly here.  But
>>  what about slightly more subtle cases?
>
>>      (funcall (compile nil '(lambda (x) (setf (cdr ',location) x))) 1)
>
> Since when can you have a comma not inside a backquote?
>
>>      (funcall (compile nil '(lambda () (setf (aref ,location 0) nil))))
>
> Err, isn't this also an error... comma without a backquote?

Whoops.  The outer quote character in both cases should be a
backquote.

Christophe