Subject: bug#40671: [DOC] modify literal objects

From: Paul Eggert <[email-masked]>
Date: Sun, 19 Apr 2020 20:23:36 -0700

On 4/19/20 5:53 PM, Michael Heerdegen wrote:
> Paul Eggert <[email-masked]> writes:
> 
>>> (let ((l (list 1 2 3)))
>>>     `',l)
>>> ==> '(1 2 3)
>>> If you evaluate this (the return value is a valid expression),
>>> `quote'
>>> returns a list, but it's not a list literal.
>>
>> Sure, but one shouldn't be modifying that list. Once you hand a Lisp
>> object to 'eval', modifying that object later ought to be a no-no even
>> if the interpreter happens to do something non-crashy now.
> 
> But I can modify the list before handing it over to `eval',
> e.g. replacing the `1' with `cons'.

Yes, that's fine. You can modify the list *before* handing it to eval, but it 
should be off limits afterwards. That is, the manual doesn't say or imply that 
the `,l yields a constant, so the result of the `,l is still modifiable. But 
once you hand the list off to eval, watch out: you shouldn't modify it.

Another way to put it is: an object can start off mutable and later become 
constant when you start using it as part of a program. Come to think of it, 
perhaps this should be added to the Constants and Mutability section. Something 
like the following patch, perhaps.

diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi
index abd258eb53..dd7eaf5ae4 100644
--- a/doc/lispref/objects.texi
+++ b/doc/lispref/objects.texi
@@ -2400,6 +2400,11 @@ Constants and Mutability
  call @code{(make-string 3 ?a)} yields a mutable string that can be
  changed via later calls to @code{aset}.

+  A mutable object can become constant if it is passed to the
+@code{eval} function, because you should not modify an object that is
+being or might be executed.  The reverse does not occur: constant
+objects should stay constant.
+
    Trying to modify a constant variable signals an error
  (@pxref{Constant Variables}).
  A program should not attempt to modify other types of constants because the

> And even when I eval the original list, I get just the same l as before:

It's OK that the interpreter does that. But you shouldn't *modify* the original 
list after handing it off to eval; it might work and it might not. You shouldn't 
even rely on the interpreter giving you the same l as before, for that matter; 
that's an implementation detail that is not documented and should not be 
documented, any more than we should document the fact that (let ((x (cos 1.5))) 
(eq x (+ x))) returns t in Emacs 27.

> We must distinguish between the objects created when a program is
> read/compiled, i.e. the objects a program consists of (data and programs
> are the same in Lisp, etc.), and the objects that that program actually
> handles when it runs.

Yes, and the basic idea is that one cannot reliably modify the objects that a 
program consists of while running the program; it's not safe. (All we need to do 
is to word this correctly and clearly. :-)