9

The Common Lisp Hyper Spec says:

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

This is further motivated at the Constant Modification Issue that lead to the corresponding clarification in the CL Spec.:

CLtL states that an implementation is permitted to "collapse" constants appearing in code to be compiled if they are EQUAL. This implicit sharing of compiled data structures may result in unpredictable behavior if destructive operations are performed. However, CLtL does not explicitly allow or disallow destructive operations on constants.

Does Emacs Lisp have the same behavior/rules as Common Lisp in that aspect?

In the Emacs Lisp Manual there are many examples where quoted lists are assigned to variables and afterwards modified.

Section "Altering the CDR of a List" gives such an example:

> (setq x '(1 2 3))
     => (1 2 3)
(setcdr x '(4))
     => (4)
x
     => (1 4)

On the other hand there is a warning not to use quoted list as non-last element of nconc in the Emacs manual:

A common pitfall is to use a quoted constant list as a non-last argument to nconc. If you do this, your program will change each time you run it! Here is what happens:

(defun add-foo (x)            ; We want this function to add
  (nconc '(foo) x))           ;   foo to the front of its arg.

(symbol-function 'add-foo)
     => (lambda (x) (nconc (quote (foo)) x))

(setq xx (add-foo '(1 2)))    ; It seems to work.
     => (foo 1 2)
(setq xy (add-foo '(3 4)))    ; What happened?
     => (foo 1 2 3 4)
(eq xx xy)
     => t

(symbol-function 'add-foo)
     => (lambda (x) (nconc (quote (foo 1 2 3 4) x)))

Is there a complete list of correct rules when to use quoted lists and when not anywhere in the Elisp manual?

Or are those examples in the Emacs manual even erroneous because they modify quoted lists?

Maybe a question of itself: Is there a Spec for Elisp?


An even more simple example for the modification of a function add-foo through the modification of its return value: (This is used in the discussion with Drew in the comments.)

(defun add-foo ()
  '(1 2 3))

(setq x (add-foo))
(setq x (nconc x 4))
(add-foo)

The last statement gives (1 2 3 . 4).

5
  • 1
    See my answer at emacs.stackexchange.com/q/45814/105.
    – Drew
    Commented Nov 7, 2018 at 15:11
  • @Drew I know that the list within add-foo and the list returned to the user are the same. Changing one changes the other (because they are actually the same). That is not the point of the question. The actual point is: What are the basic assumptions about Elisp lists where the programmer can count on? The manual gives the impression that for Emacs lists there are more restrictive assumptions than for CL implying that they give the programmer more freedom to use them. But on the other hand the manual alarms one that quoted lists are not like generated lists. AFAIK there is no clear Spec.
    – Tobias
    Commented Nov 7, 2018 at 16:09
  • The assumption about lists that you can count on is that cons and list create new list structure. Nothing more. If you think the manual gives another impression then maybe file a bug about that, maybe suggesting it's not clear. The text you cite doesn't seem problematic to me. You can certainly assign a quoted list to a variable and then modify that list. All that you need to be aware of is that you are assigning a cons and modifying that cons. The warning about nconc is just a reminder to be aware of code that modifies list structure. Changing list structure requires vigilance.
    – Drew
    Commented Nov 7, 2018 at 17:51
  • @Drew I have now cited the Constant Modification Issue from the CL-Spec. Bug Tracker that explains why it is generally a bad idea to modify quoted literal expressions in CL. Maybe the situation is different in Elisp. If so, it should be noted in the Elisp Manual which comes closest to a Spec of all what I know. The reason why I didn't file a bug report yet is that I am not sure whether there is some part of the Manual where that is explained and currently I don't have too much spare time to read it in full. BTW, thanks for being so patient with me.
    – Tobias
    Commented Nov 8, 2018 at 8:08
  • Thanks very much for that reference. I wasn't aware of it (and it's from 1988!).
    – Drew
    Commented Nov 8, 2018 at 15:26

1 Answer 1

2

The docstring for quote addresses when it should (and shouldn't) be used:

Return the argument, without evaluating it. ‘(quote x)’ yields ‘x’.

Warning: ‘quote’ does not construct its return value, but just returns the value that was pre-constructed by the Lisp reader (see info node ‘Printed Representation’).

This means that '(a . b) is not identical to (cons 'a 'b): the former does not cons. Quoting should be reserved for constants that will never be modified by side-effects, unless you like self-modifying code. See the common pitfall in info node ‘Rearrangement’ for an example of unexpected results when a quoted object is modified.

(The common pitfall mentioned in ‘Rearrangement’ is the one quoted in the question.)

As far as I can tell, no similar, broad-reaching statement is in the Emacs Lisp manual. The docstring suggests the setcdr example is if not erroneous (the behavior might be desirable), then at least potentially perplexing, as following it could lead to situations with results unexpected for those not aware of the breadth of this issue. The CONSTANT-MODIFICATION issue from the CLHS definitely applies.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.