* bug#40671: [DOC] modify literal objects @ 2020-04-16 19:28 Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 2020-04-17 16:09 ` Mattias Engdegård 2020-04-18 20:10 ` Paul Eggert 0 siblings, 2 replies; 170+ messages in thread From: Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-04-16 19:28 UTC (permalink / raw) To: 40671 Hello! The Emacs Lisp manual often gives the impression that the user can modify literal lists (e.g. 5.6.1 Altering List Elements with `setcar`). LISP> (setq x '(1 2)) (1 2) LISP> (setcar x 4) LISP> x (4 2) However, it is also mentioned that one should not modify the literal objects because of the byte compilation (c.f. 2.7 Equality Predicate). Can we modify literal objects? See Also: https://emacs.stackexchange.com/questions/45820/when-to-use-quote-for-lists-modifying-quoted-lists-in-elisp https://emacs.stackexchange.com/questions/57806/which-lisp-objects-are-byte-compiled Best regards, Kevin Vigouroux. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-16 19:28 bug#40671: [DOC] modify literal objects Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-04-17 16:09 ` Mattias Engdegård 2020-04-17 16:37 ` Mattias Engdegård 2020-04-18 20:10 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Mattias Engdegård @ 2020-04-17 16:09 UTC (permalink / raw) To: 40671; +Cc: Kevin Vigouroux >Can we modify literal objects? No, and the manual should do a much better job at explaining this. At the very least it should not promulgate ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-17 16:09 ` Mattias Engdegård @ 2020-04-17 16:37 ` Mattias Engdegård 2020-04-17 17:27 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Mattias Engdegård @ 2020-04-17 16:37 UTC (permalink / raw) To: 40671; +Cc: Kevin Vigouroux [-- Attachment #1: Type: text/plain, Size: 422 bytes --] tags 40671 patch stop [Sorry about the truncated message.] > Can we modify literal objects? No, and the manual should do a much better job at explaining this. At the very least it should not promulgate bad ideas by including mutation of literals in example code. Patch attached, suggested for emacs-27. We should not even try to show what happens when the user breaks the rule, because it is undefined. [-- Attachment #2: 0001-Don-t-mutate-literals-in-manual-examples-bug-40671.patch --] [-- Type: application/octet-stream, Size: 8588 bytes --] From 9801ee1b12574f8b1b50ba5b76b7ee41a7fb8bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org> Date: Fri, 17 Apr 2020 18:00:34 +0200 Subject: [PATCH] Don't mutate literals in manual examples (bug#40671) * doc/lispref/edebug.texi (Printing in Edebug): * doc/lispref/keymaps.texi (Changing Key Bindings): * doc/lispref/lists.texi (Setcar, Setcdr, Rearrangement, Sets And Lists) (Association Lists, Plist Access): * doc/lispref/sequences.texi (Sequence Functions, Array Functions): * doc/lispref/strings.texi (Text Comparison): Rewrite example code to not mutate constant (literal) lists, vectors or strings. Noticed by Kevin Vigouroux. --- doc/lispref/edebug.texi | 2 +- doc/lispref/keymaps.texi | 8 ++--- doc/lispref/lists.texi | 62 +++++++++----------------------------- doc/lispref/sequences.texi | 26 ++++++++-------- doc/lispref/strings.texi | 4 +-- 5 files changed, 34 insertions(+), 68 deletions(-) diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi index cfef5c12d1..5970e7cf80 100644 --- a/doc/lispref/edebug.texi +++ b/doc/lispref/edebug.texi @@ -858,7 +858,7 @@ Printing in Edebug Here is an example of code that creates a circular structure: @example -(setq a '(x y)) +(setq a (list 'x 'y)) (setcar a a) @end example diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index 2c90d208c0..fd207a184e 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -1441,10 +1441,10 @@ Changing Key Bindings @smallexample @group -(setq map '(keymap - (?1 . olddef-1) - (?2 . olddef-2) - (?3 . olddef-1))) +(setq map (list 'keymap + (cons ?1 'olddef-1) + (cons ?2 'olddef-2) + (cons ?3 'olddef-1))) @result{} (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1)) @end group diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index 27fa5385e3..d1a12e9819 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -906,7 +906,7 @@ Setcar @example @group -(setq x '(1 2)) +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -927,7 +927,7 @@ Setcar @example @group ;; @r{Create two lists that are partly shared.} -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @result{} (z b c) @@ -1017,7 +1017,7 @@ Setcdr @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1037,7 +1037,7 @@ Setcdr @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cdr (cdr x1))) @result{} (c) @@ -1069,7 +1069,7 @@ Setcdr @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cons 'd (cdr x1))) @result{} (d b c) @@ -1130,7 +1130,7 @@ Rearrangement @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1150,7 +1150,7 @@ Rearrangement @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1163,41 +1163,7 @@ Rearrangement @end group @end example -However, the other arguments (all but the last) must be lists. - -A common pitfall is to use a quoted constant list as a non-last -argument to @code{nconc}. If you do this, your program will change -each time you run it! Here is what happens: - -@smallexample -@group -(defun add-foo (x) ; @r{We want this function to add} - (nconc '(foo) x)) ; @r{@code{foo} to the front of its arg.} -@end group - -@group -(symbol-function 'add-foo) - @result{} (lambda (x) (nconc '(foo) x)) -@end group - -@group -(setq xx (add-foo '(1 2))) ; @r{It seems to work.} - @result{} (foo 1 2) -@end group -@group -(setq xy (add-foo '(3 4))) ; @r{What happened?} - @result{} (foo 1 2 3 4) -@end group -@group -(eq xx xy) - @result{} t -@end group - -@group -(symbol-function 'add-foo) - @result{} (lambda (x) (nconc '(foo 1 2 3 4) x)) -@end group -@end smallexample +However, the other arguments (all but the last) must be non-constant lists. @end defun @node Sets And Lists @@ -1260,7 +1226,7 @@ Sets And Lists @example @group -(delq 'a '(a b c)) @equiv{} (cdr '(a b c)) +(delq 'a (list 'a 'b 'c)) @equiv{} (cdr (list 'a 'b 'c)) @end group @end example @@ -1270,7 +1236,7 @@ Sets And Lists @example @group -(setq sample-list '(a b c (4))) +(setq sample-list (list 'a 'b 'c '(4))) @result{} (a b c (4)) @end group @group @@ -1407,7 +1373,7 @@ Sets And Lists @example @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(2) l) @result{} ((1)) l @@ -1416,7 +1382,7 @@ Sets And Lists ;; @r{write @code{(setq l (delete '(2) l))}.} @end group @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(1) l) @result{} ((2) (2)) l @@ -1759,7 +1725,7 @@ Association Lists than looking at the saved value of @var{alist}. @example -(setq alist '((foo 1) (bar 2) (foo 3) (lose 4))) +(setq alist (list '(foo 1) '(bar 2) '(foo 3) '(lose 4))) @result{} ((foo 1) (bar 2) (foo 3) (lose 4)) (assq-delete-all 'foo alist) @result{} ((bar 2) (lose 4)) @@ -1926,7 +1892,7 @@ Plist Access in the place where you got @var{plist}. For example, @example -(setq my-plist '(bar t foo 4)) +(setq my-plist (list 'bar t 'foo 4)) @result{} (bar t foo 4) (setq my-plist (plist-put my-plist 'foo 69)) @result{} (bar t foo 69) diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1a3a04f680..d35b4d05e3 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,7 +183,7 @@ Sequence Functions @example @group -(setq bar '(1 2)) +(setq bar (list 1 2)) @result{} (1 2) @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x '(a b c)) +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -374,11 +374,11 @@ Sequence Functions @example @group -(setq nums '(1 3 2 6 5 4 0)) +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group -(sort nums '<) +(sort nums #'<) @result{} (0 1 2 3 4 5 6) @end group @group @@ -396,7 +396,7 @@ Sequence Functions the variable that held the original list: @example -(setq nums (sort nums '<)) +(setq nums (sort nums #'<)) @end example For the better understanding of what stable sort is, consider the following @@ -1228,7 +1228,7 @@ Array Functions @example @group -(setq w [foo bar baz]) +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,12 +1237,12 @@ Array Functions @end group @group -(setq x "asdfasfd") - @result{} "asdfasfd" +(setq x (string ?a ?b ?c ?d ?e)) + @result{} "abcde" (aset x 3 ?Z) @result{} 90 x - @result{} "asdZasfd" + @result{} "abcZe" @end group @end example @@ -1257,7 +1257,7 @@ Array Functions @example @group -(setq a [a b c d e f g]) +(setq a (vector 'a 'b 'c 'd 'e 'f 'g)) @result{} [a b c d e f g] (fillarray a 0) @result{} [0 0 0 0 0 0 0] @@ -1265,10 +1265,10 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -(setq s "When in the course") - @result{} "When in the course" +(setq s (string ?S ?e ?c ?r ?e ?t)) + @result{} "Secret" (fillarray s ?-) - @result{} "------------------" + @result{} "------" @end group @end example diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 14cabc5d79..3d375409a9 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -591,7 +591,7 @@ Text Comparison @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) @result{} ("11" "1 1" "1.1" "12" "1 2" "1.2") @end group @end example @@ -608,7 +608,7 @@ Text Comparison @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX"))) @result{} ("1 1" "1 2" "1.1" "1.2" "11" "12") @end group -- 2.21.1 (Apple Git-122.3) ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-17 16:37 ` Mattias Engdegård @ 2020-04-17 17:27 ` Eli Zaretskii 0 siblings, 0 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-04-17 17:27 UTC (permalink / raw) To: Mattias Engdegård; +Cc: ke.vigouroux, 40671 > From: Mattias Engdegård <mattiase@acm.org> > Date: Fri, 17 Apr 2020 18:37:23 +0200 > Cc: Kevin Vigouroux <ke.vigouroux@laposte.net> > > > Can we modify literal objects? > > No, and the manual should do a much better job at explaining this. At the very least it should not promulgate bad ideas by including mutation of literals in example code. Patch attached, suggested for emacs-27. I don't see any explanation of the issue in the patch, did I miss something? What I see summarily replaces literal lists and cons cells with a calls to functions, and I'm not sure this is a step in the right direction. It definitely complicates the examples, which is not necessarily TRT, methodologically, for such introductory sections. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-16 19:28 bug#40671: [DOC] modify literal objects Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 2020-04-17 16:09 ` Mattias Engdegård @ 2020-04-18 20:10 ` Paul Eggert 2020-04-18 21:54 ` Drew Adams ` (2 more replies) 1 sibling, 3 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-18 20:10 UTC (permalink / raw) To: Mattias Engdegård; +Cc: Kevin Vigouroux, 40671-done [-- Attachment #1: Type: text/plain, Size: 734 bytes --] Mattias, thanks for going through the Emacs manual and looking for mistakes in this area. I know it was a pain to do that, since I did something similar in parallel and it was painful for me. I used your patch to crosscheck with my draft (finding omissions on both sides) and installed the resulting patch (attached) into the emacs-27 branch. This patch should address the points that Eli raised. That is, it adds explanations of the issue (both in the intro and the reference manual, since the issue also infects the intro), and it attempts to change examples only when the changes are needed to avoid undefined behavior in Emacs Lisp. I also kept the changes from '< to #'< that were in your patch since that's good style. [-- Attachment #2: 0001-Document-constant-vs-mutable-objects-better.patch --] [-- Type: text/x-patch, Size: 19704 bytes --] From eebfb72c906755c0a80d92c11deee7ac9faf5f4b Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sat, 18 Apr 2020 12:59:17 -0700 Subject: [PATCH] Document constant vs mutable objects better MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch builds on a suggested patch by Mattias Engdegård and on further comments by Eli Zaretskii. Original bug report by Kevin Vigouroux (Bug#40671). * doc/lispintro/emacs-lisp-intro.texi (set & setq, Review) (setcar, Lists diagrammed, Mail Aliases, Indent Tabs Mode): setq is a special form, not a function or command. * doc/lispintro/emacs-lisp-intro.texi (setcar): * doc/lispref/lists.texi (Modifying Lists, Rearrangement): * doc/lispref/sequences.texi (Sequence Functions) (Array Functions, Vectors): * doc/lispref/strings.texi (String Basics, Modifying Strings): Mention mutable vs constant objects. * doc/lispintro/emacs-lisp-intro.texi (setcar, setcdr) (kill-new function, cons & search-fwd Review): * doc/lispref/edebug.texi (Printing in Edebug): * doc/lispref/keymaps.texi (Changing Key Bindings): * doc/lispref/lists.texi (Setcar, Setcdr, Rearrangement) (Sets And Lists, Association Lists, Plist Access): * doc/lispref/sequences.texi (Sequence Functions) (Array Functions): * doc/lispref/strings.texi (Text Comparison): Fix examples so that they do not try to change constants. --- doc/lispintro/emacs-lisp-intro.texi | 32 +++++++++------ doc/lispref/edebug.texi | 2 +- doc/lispref/keymaps.texi | 8 ++-- doc/lispref/lists.texi | 60 +++++++++++++++++------------ doc/lispref/sequences.texi | 31 +++++++++------ doc/lispref/strings.texi | 17 +++++--- 6 files changed, 91 insertions(+), 59 deletions(-) diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index bd688070a3..630676d978 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -2329,7 +2329,7 @@ area. @cindex @samp{bind} defined There are several ways by which a variable can be given a value. One of -the ways is to use either the function @code{set} or the function +the ways is to use either the function @code{set} or the special form @code{setq}. Another way is to use @code{let} (@pxref{let}). (The jargon for this process is to @dfn{bind} a variable to a value.) @@ -4517,7 +4517,7 @@ number; it will be printed as the character with that @sc{ascii} code. @item setq @itemx set -The @code{setq} function sets the value of its first argument to the +The @code{setq} special form sets the value of its first argument to the value of the second argument. The first argument is automatically quoted by @code{setq}. It does the same for succeeding pairs of arguments. Another function, @code{set}, takes only two arguments and @@ -7317,11 +7317,21 @@ which leave the original list as it was. One way to find out how this works is to experiment. We will start with the @code{setcar} function. @need 1200 +@cindex constant lists +@cindex mutable lists First, we can make a list and then set the value of a variable to the -list, using the @code{setq} function. Here is a list of animals: +list, using the @code{setq} special form. Because we intend to use +@code{setcar} to change the list, this @code{setq} should not use the +quoted form @code{'(antelope giraffe lion tiger)}, as that would yield +a list that is part of the program and bad things could happen if we +tried to change part of the program while running it. Generally +speaking an Emacs Lisp program's components should be constant (or +unchanged) while the program is running. So we instead construct an +animal list that is @dfn{mutable} (or changeable) by using the +@code{list} function, as follows: @smallexample -(setq animals '(antelope giraffe lion tiger)) +(setq animals (list 'antelope 'giraffe 'lion 'tiger)) @end smallexample @noindent @@ -7398,7 +7408,7 @@ To see how this works, set the value of the variable to a list of domesticated animals by evaluating the following expression: @smallexample -(setq domesticated-animals '(horse cow sheep goat)) +(setq domesticated-animals (list 'horse 'cow 'sheep 'goat)) @end smallexample @need 1200 @@ -8846,7 +8856,7 @@ and then find the value of @code{trees}: @smallexample @group -(setq trees '(maple oak pine birch)) +(setq trees (list 'maple 'oak 'pine 'birch)) @result{} (maple oak pine birch) @end group @@ -9366,7 +9376,7 @@ For example: @smallexample @group -(setq triple '(1 2 3)) +(setq triple (list 1 2 3)) (setcar triple '37) @@ -9547,7 +9557,7 @@ part of which is the address of the next pair. The very last box points to the symbol @code{nil}, which marks the end of the list. @need 1200 -When a variable is set to a list with a function such as @code{setq}, +When a variable is set to a list via @code{setq}, it stores the address of the first box in the variable. Thus, evaluation of the expression @@ -17092,7 +17102,7 @@ reminders. @cindex Mail aliases @noindent -This @code{setq} command sets the value of the variable +This @code{setq} sets the value of the variable @code{mail-aliases} to @code{t}. Since @code{t} means true, the line says, in effect, ``Yes, use mail aliases.'' @@ -17130,8 +17140,8 @@ The following turns off Indent Tabs mode: @end smallexample Note that this line uses @code{setq-default} rather than the -@code{setq} command that we have seen before. The @code{setq-default} -command sets values only in buffers that do not have their own local +@code{setq} that we have seen before. The @code{setq-default} +sets values only in buffers that do not have their own local values for the variable. @ifinfo diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi index 8be8307c75..ec76e83db1 100644 --- a/doc/lispref/edebug.texi +++ b/doc/lispref/edebug.texi @@ -858,7 +858,7 @@ to a non-@code{nil} value. Here is an example of code that creates a circular structure: @example -(setq a '(x y)) +(setq a (list 'x 'y)) (setcar a a) @end example diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index c6a02d721f..4db9969767 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -1441,10 +1441,10 @@ Here is an example showing a keymap before and after substitution: @smallexample @group -(setq map '(keymap - (?1 . olddef-1) - (?2 . olddef-2) - (?3 . olddef-1))) +(setq map (list 'keymap + (cons ?1 olddef-1) + (cons ?2 olddef-2) + (cons ?3 olddef-1))) @result{} (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1)) @end group diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index 27fa5385e3..c2771b0165 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -866,10 +866,16 @@ foo ;; @r{@code{foo} was changed.} @node Modifying Lists @section Modifying Existing List Structure @cindex destructive list operations +@cindex constant lists +@cindex mutable lists You can modify the @sc{car} and @sc{cdr} contents of a cons cell with the primitives @code{setcar} and @code{setcdr}. These are destructive operations because they change existing list structure. +Destructive operations should be applied only to @dfn{mutable} lists, +that is, lists constructed via @code{cons}, @code{list} or similar +operations. Lists created by quoting are constants and should not be +changed by destructive operations. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -906,7 +912,7 @@ value @var{object}. For example: @example @group -(setq x '(1 2)) +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -927,7 +933,7 @@ these lists. Here is an example: @example @group ;; @r{Create two lists that are partly shared.} -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @result{} (z b c) @@ -1017,7 +1023,7 @@ reached via the @sc{cdr}. @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1037,7 +1043,7 @@ the @sc{cdr} of the first cons cell: @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cdr (cdr x1))) @result{} (c) @@ -1069,7 +1075,7 @@ of this list. @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cons 'd (cdr x1))) @result{} (d b c) @@ -1130,7 +1136,7 @@ Unlike @code{append} (@pxref{Building Lists}), the @var{lists} are @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1150,7 +1156,7 @@ list: @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1163,11 +1169,13 @@ x @end group @end example -However, the other arguments (all but the last) must be lists. +However, the other arguments (all but the last) must be mutable lists. A common pitfall is to use a quoted constant list as a non-last -argument to @code{nconc}. If you do this, your program will change -each time you run it! Here is what happens: +argument to @code{nconc}. If you do this, the resulting behavior +is undefined. It is possible that your program will change +each time you run it! Here is what might happen (though this +is not guaranteed to happen): @smallexample @group @@ -1260,7 +1268,9 @@ after those elements. For example: @example @group -(delq 'a '(a b c)) @equiv{} (cdr '(a b c)) +(equal + (delq 'a (list 'a 'b 'c)) + (cdr (list 'a 'b 'c))) @end group @end example @@ -1270,7 +1280,7 @@ removing it involves changing the @sc{cdr}s (@pxref{Setcdr}). @example @group -(setq sample-list '(a b c (4))) +(setq sample-list (list 'a 'b 'c '(4))) @result{} (a b c (4)) @end group @group @@ -1303,12 +1313,12 @@ into the variable that held the original list: (setq flowers (delq 'rose flowers)) @end example -In the following example, the @code{(4)} that @code{delq} attempts to match -and the @code{(4)} in the @code{sample-list} are not @code{eq}: +In the following example, the @code{(list 4)} that @code{delq} attempts to match +and the @code{(4)} in the @code{sample-list} are @code{equal} but not @code{eq}: @example @group -(delq '(4) sample-list) +(delq (list 4) sample-list) @result{} (a c (4)) @end group @end example @@ -1324,7 +1334,7 @@ of @code{list}. @example @group -(setq sample-list '(a b c a b c)) +(setq sample-list (list 'a 'b 'c 'a 'b 'c)) @result{} (a b c a b c) @end group @group @@ -1353,7 +1363,7 @@ Compare this with @code{memq}: @result{} (1.2 1.3) @end group @group -(memq 1.2 '(1.1 1.2 1.3)) ; @r{@code{1.2} and @code{1.2} are not @code{eq}.} +(memq (list 2) '((1) (2))) ; @r{@code{(list 2)} and @code{(2)} are not @code{eq}.} @result{} nil @end group @end example @@ -1373,11 +1383,11 @@ Compare this with @code{memq}: @example @group -(member '(2) '((1) (2))) ; @r{@code{(2)} and @code{(2)} are @code{equal}.} +(member (list 2) '((1) (2))) ; @r{@code{(list 2)} and @code{(2)} are @code{equal}.} @result{} ((2)) @end group @group -(memq '(2) '((1) (2))) ; @r{@code{(2)} and @code{(2)} are not @code{eq}.} +(memq (list 2) '((1) (2))) ; @r{@code{(list 2)} and @code{(2)} are not @code{eq}.} @result{} nil @end group @group @@ -1407,7 +1417,7 @@ For example: @example @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(2) l) @result{} ((1)) l @@ -1416,7 +1426,7 @@ l ;; @r{write @code{(setq l (delete '(2) l))}.} @end group @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(1) l) @result{} ((2) (2)) l @@ -1618,9 +1628,9 @@ keys may not be symbols: '(("simple leaves" . oak) ("compound leaves" . horsechestnut))) -(assq "simple leaves" leaves) +(assq (copy-sequence "simple leaves") leaves) @result{} nil -(assoc "simple leaves" leaves) +(assoc (copy-sequence "simple leaves") leaves) @result{} ("simple leaves" . oak) @end smallexample @end defun @@ -1759,7 +1769,7 @@ correct results, use the return value of @code{assq-delete-all} rather than looking at the saved value of @var{alist}. @example -(setq alist '((foo 1) (bar 2) (foo 3) (lose 4))) +(setq alist (list '(foo 1) '(bar 2) '(foo 3) '(lose 4))) @result{} ((foo 1) (bar 2) (foo 3) (lose 4)) (assq-delete-all 'foo alist) @result{} ((bar 2) (lose 4)) @@ -1926,7 +1936,7 @@ function returns the modified property list, so you can store that back in the place where you got @var{plist}. For example, @example -(setq my-plist '(bar t foo 4)) +(setq my-plist (list 'bar t 'foo 4)) @result{} (bar t foo 4) (setq my-plist (plist-put my-plist 'foo 69)) @result{} (bar t foo 69) diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1a3a04f680..f6faf9448c 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,7 +183,7 @@ for other ways to copy sequences. @example @group -(setq bar '(1 2)) +(setq bar (list 1 2)) @result{} (1 2) @end group @group @@ -278,7 +278,7 @@ Unlike @code{reverse} the original @var{sequence} may be modified. @example @group -(setq x '(a b c)) +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ presented graphically: For the vector, it is even simpler because you don't need setq: @example -(setq x [1 2 3 4]) +(setq x (copy-sequence [1 2 3 4])) @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -330,7 +330,7 @@ x Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly -encouraged to treat strings as immutable. +encouraged to treat strings as immutable even when they are mutable. @end defun @@ -374,11 +374,11 @@ appears in a different position in the list due to the change of @example @group -(setq nums '(1 3 2 6 5 4 0)) +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group -(sort nums '<) +(sort nums #'<) @result{} (0 1 2 3 4 5 6) @end group @group @@ -396,7 +396,7 @@ of @code{sort} and use that. Most often we store the result back into the variable that held the original list: @example -(setq nums (sort nums '<)) +(setq nums (sort nums #'<)) @end example For the better understanding of what stable sort is, consider the following @@ -1228,7 +1228,7 @@ This function sets the @var{index}th element of @var{array} to be @example @group -(setq w [foo bar baz]) +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1237,8 @@ w @end group @group -(setq x "asdfasfd") +;; @r{@code{copy-sequence} creates a mutable string.} +(setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @result{} 90 @@ -1246,6 +1247,10 @@ x @end group @end example +The @var{array} should be mutable; that is, it should not be a constant, +such as the constants created via quoting or via self-evaluating forms. +@xref{Self-Evaluating Forms}. + If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a unibyte string to multibyte if necessary to insert a character. @@ -1257,7 +1262,7 @@ each element of @var{array} is @var{object}. It returns @var{array}. @example @group -(setq a [a b c d e f g]) +(setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @result{} [0 0 0 0 0 0 0] @@ -1265,7 +1270,7 @@ a @result{} [0 0 0 0 0 0 0] @end group @group -(setq s "When in the course") +(setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @result{} "------------------" @@ -1301,7 +1306,9 @@ same way in Lisp input. A vector, like a string or a number, is considered a constant for evaluation: the result of evaluating it is the same vector. This does -not evaluate or even examine the elements of the vector. +not evaluate or even examine the elements of the vector. Vectors +written with square brackets are constants and should not be modified +via @code{aset} or other destructive operations. @xref{Self-Evaluating Forms}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 14cabc5d79..3acbf538dc 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -51,10 +51,8 @@ by a distinguished character code. operate on them with the general array and sequence functions documented in @ref{Sequences Arrays Vectors}. For example, you can access or change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, note that -@code{length} should @emph{not} be used for computing the width of a -string on display; use @code{string-width} (@pxref{Size of Displayed -Text}) instead. +and @code{aset} (@pxref{Array Functions}). However, you should not +try to change the contents of constant strings (@pxref{Modifying Strings}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -89,6 +87,9 @@ copy them into buffers. @xref{Character Type}, and @ref{String Type}, for information about the syntax of characters and strings. @xref{Non-ASCII Characters}, for functions to convert between text representations and to encode and decode character codes. +Also, note that @code{length} should @emph{not} be used for computing +the width of a string on display; use @code{string-width} (@pxref{Size +of Displayed Text}) instead. @node Predicates for Strings @section Predicates for Strings @@ -380,6 +381,10 @@ usual value is @w{@code{"[ \f\t\n\r\v]+"}}. @cindex modifying strings @cindex string modification + You can alter the contents of a mutable string via operations +described in this section. However, you should not try to use these +operations to alter the contents of a constant string. + The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} @var{idx} @var{char})} stores @var{char} into @var{string} at index @@ -591,7 +596,7 @@ for sorting (@pxref{Sequence Functions}): @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) @result{} ("11" "1 1" "1.1" "12" "1 2" "1.2") @end group @end example @@ -608,7 +613,7 @@ systems. The @var{locale} value of @code{"POSIX"} or @code{"C"} lets @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX"))) @result{} ("1 1" "1 2" "1.1" "1.2" "11" "12") @end group -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 20:10 ` Paul Eggert @ 2020-04-18 21:54 ` Drew Adams 2020-04-19 2:39 ` Noam Postavsky ` (2 more replies) 2020-04-19 2:26 ` Richard Stallman 2020-04-19 13:56 ` Eli Zaretskii 2 siblings, 3 replies; 170+ messages in thread From: Drew Adams @ 2020-04-18 21:54 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671-done OK, here's a nitpick, FWIW. ___ You say things such as this: "should be applied only to @dfn{mutable} lists, that is, lists constructed via @code{cons}, @code{list} or similar operations." That's not a usual meaning of "mutable". Your "that is" makes clear what you mean, sort of, I suppose. That part is clear enough, but it's not a good "definition" of "mutable". It's about code that always creates new list structure, versus code that might create new list structure only sometimes (e.g. the first time it's encountered). A quoted list, which you call "constant", is in fact mutable in some contexts. An immutable list would be one you couldn't ever change - it would truly be a constant. That can be true for the result of byte-compiling a quoted list. But it's not true in general for interpreted code. E.g., this example in (elisp) `Setcdr': (setq x '(1 2 3)) ⇒ (1 2 3) (setcdr x '(4)) ⇒ (4) x ⇒ (1 4) What you're really trying to convey presumably is not that one CANNOT ever modify such a list, but that one SHOULD NOT modify such a list (e.g. because of what can happen to it with the byte compiler). That's something different, and I don't think the message comes across well. Similarly: "However, the other arguments (all but the last) must be mutable lists." "MUST" means you CANNOT do otherwise. Trying to do so might result in an error being raised, for example. And that's not always the case. Hence the gotcha, hence the need for a guideline: Don't do it; just say no. That text with "must" is immediately followed by: "A common pitfall is to use a quoted constant list..." And _that's_ the point. But together with your text saying you CANNOT modify it anyway, things get confusing. Modifying a quoted list is problematic, a gotcha, a pitfall, something to avoid. You SHOULD NOT do it precisely because you CAN do it sometimes. If you couldn't, e.g., if you were prevented from doing it by always raising an error, then there would be no gotcha, no reason to tell you not to do it. Anyway, you get the idea. BTW, "a quoted constant list" is a bit poorly worded, as well. (Yes, that text was already there.) The problem is using a quoted list sexp, which can have the effect of producing a constant list. It's not about quoting a list that is somehow already a constant. Quoting can _produce_ a constant. --- FWIW, Common Lisp doesn't talk about mutable or immutable lists (or other objects): "The consequences are undefined if literal objects (including quoted objects) are destructively modified." Undefined. They CAN sometimes be destructively modified. And a proposal says to: "clarify that it is an error to destructively modify objects which are self-evaluating forms or which appear inside of a QUOTE special form." And it talks of: "modifying quoted data structures" Such wording makes clear which things we're talking about. Cltl says only: "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." Unpredictable behavior. It doesn't say it's always impossible to modify such things. It says, in effect, don't try. That's what we should say for Emacs Lisp, since we do NOT "disallow modification of constants consistently in all situations." For Emacs Lisp this is a gotcha, so we need a SHOULD. If it were enforced as a MUST then we wouldn't need such a caveat. This was proposed for CL: "Disallowing modification of constants consistently in all situations, rather than just in compiled code, is proposed because in some compiled-only situations it may be difficult to distinguish between "compiled" and "interpreted" code." Whether "disallow" means raise an error in all such cases (which was proposed for Cltl) or just warn users not to do it and say the behavior is "undefined" (what Cltl did, and what Emacs should do), is a separate question. The point about trying to modify a quoted list, for Emacs Lisp, is this: Don't do it. Don't assume that you get new list structure each time it looks like a quoted list will be evaluated anew. It might be evaluated only once, and the result used as a constant thereafter. http://clhs.lisp.se/Issues/iss083_w.htm ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 21:54 ` Drew Adams @ 2020-04-19 2:39 ` Noam Postavsky 2020-04-19 20:39 ` Paul Eggert 2020-05-01 3:03 ` Dmitry Gutov 2 siblings, 0 replies; 170+ messages in thread From: Noam Postavsky @ 2020-04-19 2:39 UTC (permalink / raw) To: Drew Adams Cc: Kevin Vigouroux, Mattias Engdegård, Paul Eggert, 40671-done On Sat, 18 Apr 2020 at 17:55, Drew Adams <drew.adams@oracle.com> wrote: > An immutable list would be one you couldn't ever > change - it would truly be a constant. That can > be true for the result of byte-compiling a quoted > list. As far as I know, byte compilation has no special effect on mutability. Dumping does, or used to, I think that no longer happens with the pdumper. . ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 21:54 ` Drew Adams 2020-04-19 2:39 ` Noam Postavsky @ 2020-04-19 20:39 ` Paul Eggert 2020-04-19 21:01 ` Drew Adams 2020-05-01 3:03 ` Dmitry Gutov 2 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-19 20:39 UTC (permalink / raw) To: Drew Adams, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 On 4/18/20 2:54 PM, Drew Adams wrote: > "should be applied only to @dfn{mutable} lists, > that is, lists constructed via @code{cons}, > @code{list} or similar operations." > > That's not a usual meaning of "mutable". Your > "that is" makes clear what you mean, sort of, I > suppose. That part is clear enough, but it's > not a good "definition" of "mutable". > > It's about code that always creates new list > structure, versus code that might create new > list structure only sometimes (e.g. the first > time it's encountered). I think we're mostly in agreement here, it's just that it can be difficult to state things clearly in a reference manual. Let me try to explain a bit further. As far as Elisp is concerned, it's OK to apply destructive operations to list structures that are created only sometimes (e.g., the first time it's encountered), so long as these structures have been created dynamically by the program. That is, the key notion is not whether the program is implementing hash-consing on its own (where it's a bad idea to modify already-existing structures but is valid as far as Elisp is concerned); the key notion here is whether the program is diving into the Lisp interpreter's data structures and attempting to change those data structures on the fly (the program shouldn't do that, as the results are unpredictable and Emacs might crash). > A quoted list, which you call "constant", is in > fact mutable in some contexts. Yes, but we cannot easily document where and when those contexts might be, and it would be a disservice to our users if we tried to document what happens exactly, partly because of the complexity and partly because the byte-compiler might change in the future. Instead, we should simply say that one should not modify the data structures that quoted lists return. > An immutable list would be one you couldn't ever > change - it would truly be a constant. That can > be true for the result of byte-compiling a quoted > list. We can talk about the distinction between a "true constant" and a "constant" in an introductory section, but in the rest of the manual it's simpler to merely distinguish between constant objects (which the program should not change) and mutable objects (which the program can change). That is, in most of the manual there's no reason to distinguish between the two: modifying a constant is trouble, and programs shouldn't do it. In the introductory section we can talk about what happens if programs try to modify a constant anyway. > "However, the other arguments (all but the last) > must be mutable lists." > > "MUST" means you CANNOT do otherwise. I changed it to "should". > BTW, "a quoted constant list" is a bit poorly > worded, as well. I changed that to "constant list". > FWIW, Common Lisp doesn't talk about mutable > or immutable lists (or other objects): > > "The consequences are undefined if literal > objects (including quoted objects) are > destructively modified." > > Undefined. They CAN sometimes be destructively > modified. Yes, that's the idea I'm trying to capture here as well, with the changes I installed today. Thanks for your comments. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 20:39 ` Paul Eggert @ 2020-04-19 21:01 ` Drew Adams 2020-04-19 21:16 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-19 21:01 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 > distinguish between constant objects (which the > program should not change) and mutable objects > (which the program can change). That's just not what "constant" means. And I suspect that your _uses_ of _not_ "mutable" will still be for things that we really want to say you probably _should not_ change, and not that you _cannot_ change them. You are once again confusing things for readers, I think. Something you probably _should not_ change is not necessarily a constant. (And the converse isn't strong enough - you simply _cannot_ change a constant.) And places where you will likely say there's no reason you _shouldn't_ change something will likely give the impression that this is because it is "mutable", and give the impression that there's no reason you shouldn't change anything that you _can_ change. This can give the impression that if you _can_ change something (the real meaning of "mutable") then there's no reason you shouldn't change it. That's the wrong message. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 21:01 ` Drew Adams @ 2020-04-19 21:16 ` Paul Eggert 2020-04-19 22:24 ` Drew Adams 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-19 21:16 UTC (permalink / raw) To: Drew Adams, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 On 4/19/20 2:01 PM, Drew Adams wrote: >> distinguish between constant objects (which the >> program should not change) and mutable objects >> (which the program can change). > That's just not what "constant" means. What does "constant" mean to you? It's not clear. > And I > suspect that your _uses_ of _not_ "mutable" will > still be for things that we really want to say > you probably _should not_ change, and not that > you _cannot_ change them. Your suspicion is correct. In the current emacs-27 documentation, "mutable" means you can change the object, "constant" means you should not change it. It's intended to be documentation that is simple and consistent and tells programmers what they can do without worrying (change a mutable object), and what they shouldn't do (try to change a constant). Of course the documentation could have a more-complex discussion of the various ways that an object could be "constant". The object could be in read-only memory enforced by the hardware and operating system, or there could be a run-time check by the Emacs interpreter, or there could be no check at all and you can change the constant with the program behaving erratically afterwards, or there are other possibilities. If you'd like to add text along those lines to the new section "Constants and Mutability" please feel free to suggest something. The point is to make that section useful for Emacs Lisp programmers, after all. > This can give the > impression that if you _can_ change something > (the real meaning of "mutable") then there's no > reason you shouldn't change it. I'm not following. Even if I've created an object with the 'cons' function there may be very good pragmatic reasons for me to not invoke setcar and setcdr on it, as otherwise my program's actions will be scrambled. However, from the Emacs lisp point of view such a cons is still mutable. If you propose specific text for the manual, no doubt your point will become clearer. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 21:16 ` Paul Eggert @ 2020-04-19 22:24 ` Drew Adams 2020-04-19 22:51 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-19 22:24 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 > >> distinguish between constant objects (which the > >> program should not change) and mutable objects > >> (which the program can change). > > > > That's just not what "constant" means. > > What does "constant" mean to you? It's not clear. Something that remains constant. You simply can't change it - impossible. The doc for `defconst' makes clear that it does _not_ define a constant, for example. In what way is what it defines a variable and not a constant? The fact that you _can_ change it. If you can change something then it's not a constant. The problem is that you're using "constant", NOT for something that CANNOT be changed, but for something that you SHOULD NOT try to change. Not the same thing. > > And I suspect that your _uses_ of _not_ "mutable" > > will still be for things that we really want to say > > you probably _should not_ change, and not that > > you _cannot_ change them. > > Your suspicion is correct. So my suspicion is correct: you're misusing "not mutable" to mean, not something that can't be changed but something that probably shouldn't be changed. See above: not mutable = constant. > In the current emacs-27 documentation, "mutable" > means you can change the object, That contradicts your statement of my suspicion being correct. If "mutable" means you can change it (which is truly what it means) then "not mutable" means you can't change it. It doesn't mean only that you probably shouldn't change it. It's the same point. mutable = changeable, not mutable = constant (not changeable). You're using "should not" in place of "cannot". Which means you're also using "no reason not to" in place of "can". And the gotcha is precisely that in some cases where you _can_, you probably _should not_. > "constant" means you should not change it. Again, a misuse. "Constant" means truly not mutable, i.e., you _cannot_ change it. The message you're giving is backward, or at least unclear. Don't say "constant". Say "don't try to change it". Not because you can't change it (not because it's constant), but because the code won't necessarily do what you expect - it might change as you think, or it might not. That's really the point, I think. > It's intended to be documentation that is simple > and consistent IMO, it's neither. Simple is to just say that you _cannot depend on_ `quote' (and some other constructs, no doubt) returning a new object, especially in code that looks like it would be evaluated multiple times. And since you can't depend on this, don't. That's the simple message: "don't do that, because it might not do what you expect" (when byte-compiled, in particular). It might (IMO) be helpful to explain that for interpreted Elisp source code what you see is what you get (is that always true?), but the same is not true for byte-compiled code. And `(quote (A B))' is a good example. We probably already say something like that (?) in other contexts: byte-compiled code may change order of evaluation or the number of times a subexpression gets evaluated - for optimization. You can't count on byte-code acting just like as source code from which it's compiled would suggest. > what they shouldn't do (try to change a constant) No one tries to change a constant. The problem - the gotcha - is that it's not always obvious when your code is trying to change a constant. In particular (but not only), beware of quoted lists. > Of course the documentation could have a more-complex > discussion of the various ways that an object could > be "constant". And somewhere in the doc that might be helpful, but only if the particular cases documented are cases we intend to keep as such. It can happen that we instead decide to keep that in the dark ("just" implementation), and we just document that whether XYZ is such a case is "undefined" - so don't count on it acting as a constant or not as a constant. > The object could be in read-only memory enforced by > the hardware and operating system, As I said earlier, there's no need to say something's a constant if it's actually enforced as a constant, in the sense that an error is raised if you try to modify it. The only cases that are problematic are those where you can think your code modifies something (anew) when in fact it might not. That's the case we're talking about wrt quoted list structure. > > And places where you will likely say there's no > > reason you _shouldn't_ change something will > > likely give the impression that this is because > > it is "mutable", and give the impression that > > there's no reason you shouldn't change anything > > that you _can_ change. This can give the > > impression that if you _can_ change something > > (the real meaning of "mutable") then there's no > > reason you shouldn't change it. > > I'm not following. By mischaracterizing not mutable as "should not be changed" (instead of "cannot be changed"), you can give the false impression that the opposite is true: if something is mutable then there's no reason you shouldn't change it. Not that the latter follows logically from the former, but by twisting the meaning of "mutable" all bets in understanding are off. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 22:24 ` Drew Adams @ 2020-04-19 22:51 ` Paul Eggert 2020-04-20 5:32 ` Drew Adams 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-19 22:51 UTC (permalink / raw) To: Drew Adams, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 On 4/19/20 3:24 PM, Drew Adams wrote: > Don't say "constant". Say "don't try to change it". That's too long and awkward a phrase for use in lots of places around the manual. We need a simple noun phrase to describe the concept; this is Documentation 101. One possible substitute is "literal object", as Mattias pointed out. Another possibility is "immutable object". Perhaps others might be better. > The only cases that are problematic are those where > you can think your code modifies something (anew) > when in fact it might not. No, that's not the only issue. If you modify some of these "constants" (or "literal objects" or whatever term you like), the behavior is undefined: Emacs can crash or remove your home directory or whatever. There is no checking. > By mischaracterizing not mutable as "should not be > changed" (instead of "cannot be changed"), you can > give the false impression that the opposite is true: > if something is mutable then there's no reason you > shouldn't change it. I don't see that false impression being given. But if it is being given, presumably the problem could be fixed by appropriate wording changes. Specific suggestions welcome. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 22:51 ` Paul Eggert @ 2020-04-20 5:32 ` Drew Adams 2020-04-22 17:36 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-20 5:32 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 > > Don't say "constant". Say "don't try to change it". > > That's too long and awkward a phrase for use in lots > of places around the manual. We need a simple noun > phrase to describe the concept; this is Documentation 101. Giving it an undefined/unexplained name doesn't describe it at all. Giving it an existing name (e.g. "constant"), which means something else, indirectly describes it incorrectly. Why do we need to say this in "lots of places around the manual"? Explain the gotcha in one place, and if need to refer to that explanation elsewhere then do so (link). > One possible substitute is "literal object", as Mattias > pointed out. Another possibility is "immutable object". > Perhaps others might be better. As I explained, none of those correspond to what I think the gotcha is. > > The only cases that are problematic are those where > > you can think your code modifies something (anew) > > when in fact it might not. > > No, that's not the only issue. If you modify some of > these "constants" (or "literal objects" or whatever > term you like), the behavior is undefined: Emacs can > crash or remove your home directory or whatever. If Emacs can crash or remove your home directory, that's a bug, IMO. We don't document bugs, and we certainly shouldn't let Emacs crash and just tell you not to do XYZ because of that. Saying the behavior in some case is not defined means (usually) that we're not going to support/guarantee what the behavior is in that case, and we're not going to detail/say what it is. Saying some behavior is undefined is never (in my experience) done knowing it crashes the program. > There is no checking. If that's what's meant then say that. The explanation of the gotcha should, IMO, include a simple example of quoting a list: '(1 2 3), and then modifying some of that list structure. Say what can happen, e.g. with byte-compilation, and how that's different from what one might expect if '(1 2 3) is incorrectly thought of as always creating new list structure each time that code is evaluated. Maybe say that just reading the '(1 2 3) creates a list, and that thereafter that same list is used by the byte compiler. The point in showing a simple list example is to help make clear what's going on. More importantly, the quoted-list version of the gotcha is the common one. I don't want to belabor this. If you don't get what I'm saying then perhaps someone else will be willing to explain it better than I. Or if what I've said is unclear also to others, or is judged wrong, then please forget about it. To me, it's pretty simple in terms of effect: You write '(1 2 3), and you mistakenly think you've essentially written code that does what (list 1 2 3) does: creates a new list each time the code it's in gets evaluated. Maybe that '(1 2 3) code is in a context where it (looks like it) gets evaluated more than once. You think you're getting a new list (new conses) each time. Some other code modifies the list (e.g. using setcar). You think that code is modifying a new list each time, but it's not - it's modifying the same cons. Gotcha. There are no doubt other scenarios that exhibit essentially the same gotcha. But I don't think it's necessary to detail them all. What's needed is to provide the warning, some general description of the problem, and/or a simple example (using a list). ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 5:32 ` Drew Adams @ 2020-04-22 17:36 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-22 17:36 UTC (permalink / raw) To: Drew Adams, Mattias Engdegård; +Cc: Kevin Vigouroux, 40671 On 4/19/20 10:32 PM, Drew Adams wrote: > Giving it an existing name (e.g. "constant"), which means > something else In informal language the word "constant" can mean different things to different people. If the manual defines the word "constant" to mean "an object whose value should never change" and it uses that word consistently, then that's OK; the manual's terminology corresponds closely enough to the informal one. Of course if we can come up with a better phrase than "constant" then we should use that; but so far we haven't seemed to be able to. > Explain the gotcha in one place, and if > need to refer to that explanation elsewhere then do so > (link). Yes, that's what's done now. > If Emacs can crash or remove your home directory, > that's a bug, IMO. We don't document bugs We should advise Lisp programmers about what they can do safely, and what they should not do due to Emacs's unfortunate limitations. We already do this in other dangerous areas (e.g., what happens if you increase max-lisp-eval-depth too far), and we should do it in this dangerous area too. You're right that we needn't document in detail what happens if a Lisp program does unsafe things. > we certainly shouldn't let Emacs crash If we can fix the problem that would be better, yes. However, it's not practical to do that for Emacs 27 because it is so close to release and any fix would require major surgery. It's not clear that it's practical to fix things even for Emacs 28. > Saying some behavior > is undefined is never (in my experience) done knowing > it crashes the program. Welcome to the wonderful world of undefined behavior. I'm joking of course; undefined behavior is not a good thing. But here we are. > Maybe say that just reading the '(1 2 3) creates a > list, and that thereafter that same list is used by > the byte compiler. Thanks, I'll add something along those lines. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 21:54 ` Drew Adams 2020-04-19 2:39 ` Noam Postavsky 2020-04-19 20:39 ` Paul Eggert @ 2020-05-01 3:03 ` Dmitry Gutov 2020-05-01 5:16 ` Drew Adams 2020-05-01 21:46 ` Paul Eggert 2 siblings, 2 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-01 3:03 UTC (permalink / raw) To: Drew Adams, Paul Eggert, Mattias Engdegård Cc: Kevin Vigouroux, 40671-done On 19.04.2020 00:54, Drew Adams wrote: > It's about code that always creates new list > structure, versus code that might create new > list structure only sometimes (e.g. the first > time it's encountered). Could we call them "interned values"? Like "interned strings" in some programming languages. And then say "don't try to modify them please". The "sometimes" aspect is a semantic snag, but it's certainly better than calling them constant. "literal values" is also an option, but that definition seems limiting. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 3:03 ` Dmitry Gutov @ 2020-05-01 5:16 ` Drew Adams 2020-05-01 21:46 ` Paul Eggert 1 sibling, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-05-01 5:16 UTC (permalink / raw) To: Dmitry Gutov, Paul Eggert, Mattias Engdegård Cc: Kevin Vigouroux, 40671-done > > It's about code that always creates new list > > structure, versus code that might create new > > list structure only sometimes (e.g. the first > > time it's encountered). > > Could we call them "interned values"? Like "interned strings" in some > programming languages. And then say "don't try to modify them please". > > The "sometimes" aspect is a semantic snag, but it's certainly better > than calling them constant. > > "literal values" is also an option, but that definition seems limiting. You're replying to a message of mine from a while back. I agree with the limitation or difficulty of communicating the "sometimes" aspect. And I agree that the message for users should be "don't try to modify them" (even though the "them" isn't detailed). My own opinion is to avoid mention of any such name: constant, literal, interned this-or-that. Better to keep it vague, and just sketch the problem and say that the behavior is undefined. IMO, the message for users for the quoted-list gotcha should be to not assume that code that has a quoted list in it creates a new list whenever you might think that that code (Lisp source or byte-compiled) gets evaluated. `quote' returns its arg unevaluated, but it's not always clear by looking at the source code just when or how many times a quoted list might get evaluated. That's undefined, so assume nothing about it. In particular, the behavior can differ for the same source code, depending on whether it's interpreted or byte-compiled. A simple example could suffice, to make that point. If it helps, we can also say, for the example, that the source-code quoted list might, in effect, get replaced by its value when it's read or byte-compiled, so the same cons cells (not new list structure) might get reused each time the resulting code gets evaluated. And because of that possibility you're advised not to try to modify such a list. Yes, there are other examples of the problem, besides quoted lists. Like the Common Lisp doc, we could list some of them, without giving more examples or going into detail. Or we could give a second simple example, perhaps with a string literal. What's important, I think, is to (1) get across the general idea/problem, (2) give some idea how to recognize situations where the gotcha can arise, and make clear that you cannot depend on the behavior. There's no prevention of the gotcha, e.g. by raising an error systematically. You just have to learn to recognize the possibility of trying to modify something that may have become, at some point, effectively unmodifiable - and not do that. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 3:03 ` Dmitry Gutov 2020-05-01 5:16 ` Drew Adams @ 2020-05-01 21:46 ` Paul Eggert 2020-05-01 23:37 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-01 21:46 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams, Mattias Engdegård Cc: Kevin Vigouroux, 40671-done On 4/30/20 8:03 PM, Dmitry Gutov wrote: > Could we call them "interned values"? Like "interned strings" in some > programming languages. "Interned" would imply that we're merely deduplicating objects by hashing their contents, which means modifying one deduplicated object modifies them all. But the problem is bigger than that. There are some objects that one simply should not modify, even if they are not deduplicated. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 21:46 ` Paul Eggert @ 2020-05-01 23:37 ` Dmitry Gutov 0 siblings, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-01 23:37 UTC (permalink / raw) To: Paul Eggert, Drew Adams, Mattias Engdegård Cc: Kevin Vigouroux, 40671-done On 02.05.2020 00:46, Paul Eggert wrote: > On 4/30/20 8:03 PM, Dmitry Gutov wrote: >> Could we call them "interned values"? Like "interned strings" in some >> programming languages. > "Interned" would imply that we're merely deduplicating objects by hashing their > contents, which means modifying one deduplicated object modifies them all. But > the problem is bigger than that. There are some objects that one simply should > not modify, even if they are not deduplicated. True. It's just the closest term from other languages I know that I could think of. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 20:10 ` Paul Eggert 2020-04-18 21:54 ` Drew Adams @ 2020-04-19 2:26 ` Richard Stallman 2020-04-19 13:56 ` Eli Zaretskii 2 siblings, 0 replies; 170+ messages in thread From: Richard Stallman @ 2020-04-19 2:26 UTC (permalink / raw) To: Paul Eggert; +Cc: ke.vigouroux, eggert, 40671 [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] Thanks to both of you for working on updating the Emacs Lisp Intro. Its author, Bob Chassell, became incapacitated many years before his death, so it has not had the needed attention for quite some time. I would be surprised if it didn't have other problems due to the changes that we have made in Emacs Lisp since 20 years ago. Would anyone like to pick some chapter and read it looking for anything that needs updating? Not only things that are now incorrect, but anything that is not clear to beginners. -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-18 20:10 ` Paul Eggert 2020-04-18 21:54 ` Drew Adams 2020-04-19 2:26 ` Richard Stallman @ 2020-04-19 13:56 ` Eli Zaretskii 2020-04-19 16:59 ` Mattias Engdegård 2020-04-19 20:45 ` Paul Eggert 2 siblings, 2 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-04-19 13:56 UTC (permalink / raw) To: Paul Eggert; +Cc: mattiase, 40671, ke.vigouroux > Cc: 40671-done@debbugs.gnu.org, Kevin Vigouroux <ke.vigouroux@laposte.net>, > Eli Zaretskii <eliz@gnu.org> > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Sat, 18 Apr 2020 13:10:30 -0700 > > Mattias, thanks for going through the Emacs manual and looking for mistakes in > this area. I know it was a pain to do that, since I did something similar in > parallel and it was painful for me. I used your patch to crosscheck with my > draft (finding omissions on both sides) and installed the resulting patch > (attached) into the emacs-27 branch. > > This patch should address the points that Eli raised. How do you know the patch addresses my concerns, when you didn't even let me read and comment on it? What is this rush to go ahead and push changes when there's clearly some controversy that hasn't yet been resolved? Can I somehow convince you not to do that in the future? > That is, it adds explanations of the issue (both in the intro and > the reference manual, since the issue also infects the intro), and > it attempts to change examples only when the changes are needed to > avoid undefined behavior in Emacs Lisp. As Štěpán points out, not all of the examples need these changes. Please revert the changes that aren't needed. More generally, it is IMO not enough to explain the issue in one place, and then use non-literal constructs everywhere as if the reader magically knows or remembers something that is written in a very far place of the manual. The effect is to obfuscate the manual without any explanation right there and then -- which is IMNSHO a very bad thing, methodologically, because it leaves the readers wondering what they are missing. For example, the node "Sets and Lists" now sometimes uses literal lists and sometimes non-literal ones -- without any explanation why. Likewise in "Association Lists" and "Sequence Functions". This is a step backward. We are making our manual a riddle that the reader will have to solve. That is not how good manuals are written. > @example > @group > -(delq 'a '(a b c)) @equiv{} (cdr '(a b c)) > +(equal > + (delq 'a (list 'a 'b 'c)) > + (cdr (list 'a 'b 'c))) > @end group And here you simply changed the meaning of the example: @equiv{} is not the same as 'equal'. Bottom line: the extra explanations about the danger of using literal lists in some situations are a good addition to the manual, but most of the replacements elsewhere of literal lists with non-literal ones are not -- unless we also add in each case some text which explains why we use 'list', 'cons', 'vector', etc, instead of literal constants. Please fix these deficiencies. Thanks in advance. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 13:56 ` Eli Zaretskii @ 2020-04-19 16:59 ` Mattias Engdegård 2020-04-19 19:21 ` Eli Zaretskii 2020-04-19 21:02 ` Paul Eggert 2020-04-19 20:45 ` Paul Eggert 1 sibling, 2 replies; 170+ messages in thread From: Mattias Engdegård @ 2020-04-19 16:59 UTC (permalink / raw) To: Eli Zaretskii; +Cc: ke.vigouroux, Paul Eggert, 40671 19 apr. 2020 kl. 15.56 skrev Eli Zaretskii <eliz@gnu.org>: > This is a step backward. We are making our manual a riddle that the > reader will have to solve. That is not how good manuals are written. Eli, maybe that is stretching it a bit? Paul's (and my) changes are far from perfect but they did aim to do no harm. Surely we all prefer correct to simple and wrong. Mistakes must and will be fixed, naturally. Your point about not surprising the user about inconsistencies in examples is entirely fair, and we should definitely explain these issues more clearly and in the right order. However, it doesn't mean that the status quo ante was better: not only did the manual set bad examples in many places, it even managed to warn sternly about non-constant arguments to nconc right after an example which did precisely that. What about we add a separate section about literals of all types, why they should be treated as immutable even though mutation currently isn't detected or disallowed at runtime, and recommended ways of coping with it (constructor functions, copy-sequence)? It would serve as a point of reference for all sections describing destructive operations. There is also a need for some cautionary text in the backquote section. I'd volunteer to write it all but won't do the work just to have it shot down on general principles. It's not like I'm expecting a blank cheque, but we'd need to agree on the approach first. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 16:59 ` Mattias Engdegård @ 2020-04-19 19:21 ` Eli Zaretskii 2020-04-19 21:02 ` Paul Eggert 1 sibling, 0 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-04-19 19:21 UTC (permalink / raw) To: Mattias Engdegård; +Cc: ke.vigouroux, eggert, 40671 > From: Mattias Engdegård <mattiase@acm.org> > Date: Sun, 19 Apr 2020 18:59:55 +0200 > Cc: Paul Eggert <eggert@cs.ucla.edu>, 40671@debbugs.gnu.org, > ke.vigouroux@laposte.net > > 19 apr. 2020 kl. 15.56 skrev Eli Zaretskii <eliz@gnu.org>: > > > This is a step backward. We are making our manual a riddle that the > > reader will have to solve. That is not how good manuals are written. > > Eli, maybe that is stretching it a bit? Paul's (and my) changes are far from perfect but they did aim to do no harm. Surely we all prefer correct to simple and wrong. Mistakes must and will be fixed, naturally. The problem is that the changes were pushed before they could be reviewed and commented. No one said anything about meaning to do harm, but mistakes do happen, and a good way to avoid mistakes is to let peer review take its course. Rushing a commit doesn't allow to make the changes better by considering aspects that the original committer was unaware of, or where he/she is biased or lacks some knowledge or experience that others can contribute. > Your point about not surprising the user about inconsistencies in examples is entirely fair, and we should definitely explain these issues more clearly and in the right order. However, it doesn't mean that the status quo ante was better: not only did the manual set bad examples in many places, it even managed to warn sternly about non-constant arguments to nconc right after an example which did precisely that. I stand by what I wrote: the status quo ante was better. A manual is not a mathematical paper, where everything should be rigorous all the way from the first page to the last. A good manual introduces the material gradually, and makes simplifications to avoid dumping too much stuff on the reader at once. So yes, it is entirely legitimate to show simplified examples, and at some later point say that those simple examples have pitfalls, and explain those pitfalls. There's absolutely no requirement to be 110% correct everywhere in the manual, because that will make the manual hard to read and understand, and eventually will shoot us in the foot. This is, of course, my opinion. Your opinions might be different, and maybe you could convince me in some of the cases. But for this to happen, we need to talk, and you (or Paul) need to present the arguments that aim at changing my mind (or change your own). Is it too much to ask to let the discussion proceed? If these matters are important, then we should give their discussion our best shot, so that the net result is absolutely the best we could come up with -- and that means it should incorporate the different views and experiences of most or all the participants. > What about we add a separate section about literals of all types, why they should be treated as immutable even though mutation currently isn't detected or disallowed at runtime, and recommended ways of coping with it (constructor functions, copy-sequence)? It would serve as a point of reference for all sections describing destructive operations. There is also a need for some cautionary text in the backquote section. > > I'd volunteer to write it all but won't do the work just to have it shot down on general principles. It's not like I'm expecting a blank cheque, but we'd need to agree on the approach first. I don't think I understand the proposal enough to answer the question. Wed already have a section about these matters, and the additions that Paul made there are more or less uncontroversial, I think, and generally consider a Good Thing. What do you suggest in addition to that? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 16:59 ` Mattias Engdegård 2020-04-19 19:21 ` Eli Zaretskii @ 2020-04-19 21:02 ` Paul Eggert 2020-04-19 21:11 ` Drew Adams 2020-04-19 21:57 ` Michael Heerdegen 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-19 21:02 UTC (permalink / raw) To: Mattias Engdegård, Eli Zaretskii; +Cc: ke.vigouroux, 40671 On 4/19/20 9:59 AM, Mattias Engdegård wrote: > What about we add a separate section about literals of all types, why they should be treated as immutable even though mutation currently isn't detected or disallowed at runtime, and recommended ways of coping with it (constructor functions, copy-sequence)? It would serve as a point of reference for all sections describing destructive operations. In my recent patches to the emacs-27 branch I added a section "Constants and Mutability" that discusses many of these issues. It's a fundamental topic so I put the new section into doc/lispref/objects.texi, and cross-referenced it from the destructive-operation sections. I didn't think of recommending ways of coping with it, and that's a good suggestion. I'm not sure that the coping-mechanism discussion belongs in objects.texi, though, as it's pragmatic rather than fundamental. > There is also a need for some cautionary text in the backquote section. Yes, my recent patches added a brief note there. > I'd volunteer to write it all but won't do the work just to have it shot down on general principles. I know the feeling. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 21:02 ` Paul Eggert @ 2020-04-19 21:11 ` Drew Adams 2020-04-19 21:57 ` Michael Heerdegen 1 sibling, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-04-19 21:11 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård, Eli Zaretskii; +Cc: ke.vigouroux, 40671 > In my recent patches to the emacs-27 branch I added a section > "Constants and Mutability" that discusses many of these issues. See my previous reply. It's not about (what you called) constants and mutability. Misleading, and unclear, IMO. > I didn't think of recommending ways of coping with it I don't think that's needed. That is, I don't think there's any such "coping". What's needed is to make clear to users _what_ happens, and its effects; that's all. With that info, they can do whatever's appropriate for them in any given context. But it's good to show an example of a gotcha, to help make clear _what_ can happen and why. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 21:02 ` Paul Eggert 2020-04-19 21:11 ` Drew Adams @ 2020-04-19 21:57 ` Michael Heerdegen 2020-04-19 22:41 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-04-19 21:57 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Hello Paul, I had a quick look at your changes. I agree that it would have been better to discuss before you start to install what you think you like. Some things add more confusion. Before your changes the manual used the term "literal" objects, now you added a different wording "constant" vs. "mutable" that describes more or less the same thing. Then some things you added are just wrong, at least in the generality you word them. As Drew said, `quote' doesn't always return constant objects, the special form just returns the OBJECT, whatever it is, when it is evaluated. Or: | Vectors written with square brackets are constants and should not be | modified via @code{aset} or other destructive operations. (let ((l (list 1 2 3))) (let ((my-vector `[,@l])) my-vector)) What does this sentence tell me about the vector I constructed? We should really be super careful with these changes. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 21:57 ` Michael Heerdegen @ 2020-04-19 22:41 ` Paul Eggert 2020-04-19 23:45 ` Michael Heerdegen 2020-04-20 6:02 ` Drew Adams 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-19 22:41 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/19/20 2:57 PM, Michael Heerdegen wrote: > I had a quick look at your changes. I agree that it would have been > better to discuss before you start to install what you think you like. Yes, in hindsight I suppose you're right. If you like I can revert the changes now. > Before your changes the manual used the > term "literal" objects, now you added a different wording "constant" > vs. "mutable" that describes more or less the same thing. Thanks, I hadn't recalled that use of "literal object" (in the Equality Predicates) section. Although the two notions are related they're not identical. For example, the reason one shouldn't modify byte-code objects is not the sharing issue mentioned in Equality Predicates: it's because doing so can make Emacs crash. That being said, it would be helpful discuss the two notions in a unified way rather than separately, as is the case now. > Then some things you added are just wrong, at least in the generality > you word them. As Drew said, `quote' doesn't always return constant > objects, the special form just returns the OBJECT, whatever it is, when > it is evaluated. It depends on what one means by "constant" objects. If we uniformly changed that word to "literal" would that remove the objection? For example, although byte-code objects aren't normally what one would think of as being "literal", we could simply define them to be "literal". > | Vectors written with square brackets are constants and should not be > | modified via @code{aset} or other destructive operations. > > (let ((l (list 1 2 3))) > (let ((my-vector `[,@l])) > my-vector)) > > What does this sentence tell me about the vector I constructed? Nothing, just as the documentation for splicing also says nothing about that vector. These are both deficiencies in the documentation that should get fixed (and in some form the deficiencies both predate the recent changes). ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 22:41 ` Paul Eggert @ 2020-04-19 23:45 ` Michael Heerdegen 2020-04-20 0:24 ` Paul Eggert 2020-04-21 1:25 ` Michael Heerdegen 2020-04-20 6:02 ` Drew Adams 1 sibling, 2 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-04-19 23:45 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > Yes, in hindsight I suppose you're right. If you like I can revert the > changes now. I can't estimate, for me it is enough if you are willing to revert if there is no consent and we discuss all of this now. > > Before your changes the manual used the > > term "literal" objects, now you added a different wording "constant" > > vs. "mutable" that describes more or less the same thing. > > Thanks, I hadn't recalled that use of "literal object" (in the > Equality Predicates) section. Although the two notions are related > they're not identical. For example, the reason one shouldn't modify > byte-code objects is not the sharing issue mentioned in Equality > Predicates: it's because doing so can make Emacs crash. > That being said, it would be helpful discuss the two notions in a > unified way rather than separately, as is the case now. I would like to leave the suggestion of a good wording to someone like Stefan, feeling not competent enough myself. I have just the feeling sure if you simplify too much. Lisp has reading, compiling, evaluation. When the reader reads something like '(x y z), the (x y z) already produces the literal thing because the reader transforms it into an object, contrarily to creation of objects at run-time. The compiler can handle it differently. That's the main difference. The quote comes into play when the thing gets evaluated. When you evaluate the expression, the literal is returned. It could also end up as part of a program, which was the pitfall case in the initial report. > > Then some things you added are just wrong, at least in the generality > > you word them. As Drew said, `quote' doesn't always return constant > > objects, the special form just returns the OBJECT, whatever it is, when > > it is evaluated. > > It depends on what one means by "constant" objects. If we uniformly > changed that word to "literal" would that remove the objection? For > example, although byte-code objects aren't normally what one would > think of as being "literal", we could simply define them to be > "literal". No, that's not (only) what I mean. Maybe you should remember how quote is used in `defmacro's for example? Generally it's just a mean to prevent evaluation. In your examples this returned the literal notated after the quote, but it can be anything. Or - about what do you speak? The part of the program being quoted, or the thing "behind" the quote when the program is executed? When you describe the return value of quote, the special form, in the docstring, you are speaking about the latter, and then this is wrong, the return value is the arbitrary OBJECT. E.g. (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. But if you try to modify what the reader constructed after reading ",l", also a list (\, l), you'll probably get a problem. As a special case, quote can be used to create lists because Lisp programs are lists and use list notation anyway. But that's only one way of using it. > > | Vectors written with square brackets are constants and should not be > > | modified via @code{aset} or other destructive operations. > > (let ((l (list 1 2 3))) > > (let ((my-vector `[,@l])) > > my-vector)) > > What does this sentence tell me about the vector I constructed? > > Nothing, just as the documentation for splicing also says nothing > about that vector. One could read your sentence as suggesting that `my-vector' would be constant because square brackets are used to construct it. This was an example to demonstrate where your wording is too vague in my opinion. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 23:45 ` Michael Heerdegen @ 2020-04-20 0:24 ` Paul Eggert 2020-04-20 0:53 ` Michael Heerdegen 2020-04-21 1:25 ` Michael Heerdegen 1 sibling, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-20 0:24 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/19/20 4:45 PM, Michael Heerdegen wrote: > I have just the feeling sure if you simplify too much. Lisp has > reading, compiling, evaluation.... Yes, it can be complicated under the hood. The current section attempts to document this conservatively, saying "If your program does this it'll be safe." It does not attempt to document much of what happens if you step outside the "safe" boundaries (i.e., if you attempt to modify "constants" - to use the current terminology). One can indeed imagine more-detailed documentation about what happens if you modify constants. However, I didn't have the time or inclination to document the details there, and on the whole I think this was the right decision. It's not a win to greatly complicate the Elisp documentation to cover iffy edge-cases that code shouldn't be exploring anyway. On the contrary, we should leave things unspecified in this dangerous area, to give future implementers more freedom to improve Emacs. > (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. Otherwise we're placing too many constraints on the Lisp implementation (which can crash even now if you play this sort of game). >>> | Vectors written with square brackets are constants and should not be >>> | modified via @code{aset} or other destructive operations. >>> (let ((l (list 1 2 3))) >>> (let ((my-vector `[,@l])) >>> my-vector)) >>> What does this sentence tell me about the vector I constructed? >> >> Nothing, just as the documentation for splicing also says nothing >> about that vector. > > One could read your sentence as suggesting that `my-vector' would be > constant because square brackets are used to construct it. This was an > example to demonstrate where your wording is too vague in my opinion. OK, how about if we append the following sentence to that section: As an exception to the above rules, a vector within a backquote construct is not considered to be a constant if it contains a substitution or splice. That is, the backquote causes the vector to (a) not be considered a constant, (b) be newly created each time the backquote is evaluated, and (c) mutable. The (a) and (b) parts fix problems that were already there in the longstanding documentation; the (c) part is new. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 0:24 ` Paul Eggert @ 2020-04-20 0:53 ` Michael Heerdegen 2020-04-20 3:23 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-04-20 0:53 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> 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'. And even when I eval the original list, I get just the same l as before: (let ((l (list 1 2 3))) `',l (eq l (eval `',l))) ==> t. AFAIU the problematic entities are the literal lists created by the reader and the compiler. > >>> (let ((l (list 1 2 3))) > >>> (let ((my-vector `[,@l])) > >>> my-vector)) > OK, how about if we append the following sentence to that section: > > As an exception to the above rules, a vector within a backquote construct > is not considered to be a constant if it contains a substitution or splice. > That is, the backquote causes the vector to (a) not be considered a > constant, (b) be newly created each time the backquote is evaluated, > and (c) mutable. The (a) and (b) parts fix problems that were already > there in the longstanding documentation; the (c) part is new. Here your perspective becomes complicated. The Lisp reader reads the vector [,@l] while reading the program. That vector is never used by the program, because already the expansion of the code does not include a vector any more: (macroexpand-all '(let ((l (list 1 2 3))) (let ((my-vector `[,@l])) my-vector))) ==> (let ((l (list 1 2 3))) (let ((my-vector (vconcat l))) my-vector)) Only symbols, numbers, and lists. Any other macro could do something similar, so backquote is not just an exception, and was only an example that came to my mind first. If the definition of backquote would try to modify the read [,@l] vector, this vector of length 1, we would have a problem. But it only analyses this vector to produce some other code that doesn't even contain a vector any more. 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. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 0:53 ` Michael Heerdegen @ 2020-04-20 3:23 ` Paul Eggert 2020-04-20 3:36 ` Michael Heerdegen 2020-04-20 5:54 ` Drew Adams 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-20 3:23 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/19/20 5:53 PM, Michael Heerdegen wrote: > Paul Eggert <eggert@cs.ucla.edu> 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. :-) ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 3:23 ` Paul Eggert @ 2020-04-20 3:36 ` Michael Heerdegen 2020-04-22 6:30 ` Paul Eggert 2020-04-20 5:54 ` Drew Adams 1 sibling, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-04-20 3:36 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > + 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. > + I don't know if what you say about the interpreter is true (I hope it is not), and I must really go to bed now, but "you should not modify an object that is being or might be executed" - isn't that quite common when calculating macro expansions (which, typically, are executed)? Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 3:36 ` Michael Heerdegen @ 2020-04-22 6:30 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-22 6:30 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/19/20 8:36 PM, Michael Heerdegen wrote: > Paul Eggert <eggert@cs.ucla.edu> writes: > >> + 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. >> + > > I don't know if what you say about the interpreter is true (I hope it is > not), Unfortunately it is true, for performance reasons: you can't reliably change a form that is currently being executed by the Lisp interpreter. This is because the interpreter can cache parts of such forms, or can check forms and later execute them under the assumption that the checks succeeded, and if the caches are invalid or the earlier checks no longer apply then Emacs can dump core or worse. > "you should not modify an > object that is being or might be executed" - isn't that quite common > when calculating macro expansions (which, typically, are executed)? You can modify the object before giving it to 'eval' (and macro expansion can do modifications like that), but you shouldn't modify it while it's being evaluated. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 3:23 ` Paul Eggert 2020-04-20 3:36 ` Michael Heerdegen @ 2020-04-20 5:54 ` Drew Adams 2020-04-22 17:21 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-20 5:54 UTC (permalink / raw) To: Paul Eggert, Michael Heerdegen Cc: Mattias Engdegård, 40671, ke.vigouroux > Another way to put it is: an object can start off mutable and later > become constant I don't like that formulation at all. You must instead be talking about different objects. A mutable object cannot be changed to a constant, AFAIK. I think the gotcha we're talking about is thinking that a particular object is mutable when it's not. > +A mutable object can become constant if it is passed to the > +@code{eval} function, How so? What's an example? > +because you should not modify an object that is > +being or might be executed. I don't think it even makes any sense to say that something can become something else _because you should not do XYZ_. That parses - is grammatical, but it makes no sense. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-20 5:54 ` Drew Adams @ 2020-04-22 17:21 ` Paul Eggert 2020-04-23 0:49 ` Michael Heerdegen 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-22 17:21 UTC (permalink / raw) To: Drew Adams, Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/19/20 10:54 PM, Drew Adams wrote: > A mutable object cannot be changed to a constant Sure they can. This idea is common in other languages, e.g., see Object.freeze method in JavaScript. There's no reason Emacs Lisp can't use the idea. >> +A mutable object can become constant if it is passed to the >> +@code{eval} function, > > How so? What's an example? (let ((x (make-string 1 ?a))) (eval `(progn (defun foo () (let ((a ,x)) (aset x 0 ?b) (list a "a" (equal a "a")))) (byte-compile 'foo) (foo)))) This code is not well-formed because it modifies the string x after passing it to eval (such strings should be constant). As a result, the behavior of the program is unpredictable. On master it currently yields ("b" "b" t) but there's no guarantee of this. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-22 17:21 ` Paul Eggert @ 2020-04-23 0:49 ` Michael Heerdegen 2020-04-24 2:36 ` Richard Stallman 2020-04-25 2:22 ` Paul Eggert 0 siblings, 2 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-04-23 0:49 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > > A mutable object cannot be changed to a constant > > Sure they can. This idea is common in other languages, e.g., see > Object.freeze method in JavaScript. There's no reason Emacs Lisp can't > use the idea. Ok. I still have questions and objections about your additions: + 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. `eval' is used quite rarely. Can what you describe happen under other circumstances, or does it only happen to `eval'? E.g. what about this case for example: (let ((l (list 1 2 3))) (funcall (lambda () l))) Has the list become a constant? I ask because the sub-clause "because you should not modify an object that is being or might be executed" is totally different statement than that about `eval'. A list literal (1 2 3) or a string as in the example in your answer to Drew are surely not executed, as they are not valid forms. They are part of a program. But anything a macro generates also becomes part of a program. Maybe I misread "might be executed" as "might be executed in the future" and you actually meant something like "might (currently) be executed (as part of the expression the interpreter currently executes). BTW, speaking about Lisp the term "evaluate" is probably preferable to "execute" I think. Thanks, Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-23 0:49 ` Michael Heerdegen @ 2020-04-24 2:36 ` Richard Stallman 2020-04-24 15:08 ` Drew Adams 2020-04-24 16:39 ` Mattias Engdegård 2020-04-25 2:22 ` Paul Eggert 1 sibling, 2 replies; 170+ messages in thread From: Richard Stallman @ 2020-04-24 2:36 UTC (permalink / raw) To: Michael Heerdegen; +Cc: mattiase, eggert, 40671, ke.vigouroux [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] It seems strange to use the terms "constant" and "mutable" to describe whether modifying its contents is something you had better avoid. I think people will find that terminology confusing. Normally "mutable" means that you CAN change it, not that it is OK to change it. -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 2:36 ` Richard Stallman @ 2020-04-24 15:08 ` Drew Adams 2020-04-25 1:58 ` Paul Eggert 2020-04-24 16:39 ` Mattias Engdegård 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-24 15:08 UTC (permalink / raw) To: rms, Michael Heerdegen; +Cc: mattiase, eggert, 40671, ke.vigouroux > It seems strange to use the terms "constant" and "mutable" to describe > whether modifying its contents is something you had better avoid. > I think people will find that terminology confusing. Normally > "mutable" means that you CAN change it, not that it is OK to change it. Yes. Precisely what I, Michael, and others said. The message should be one of advice/guidance: explaining a gotcha, or at least suggesting what to avoid. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 15:08 ` Drew Adams @ 2020-04-25 1:58 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-25 1:58 UTC (permalink / raw) To: Drew Adams, rms, Michael Heerdegen; +Cc: mattiase, 40671, ke.vigouroux On 4/24/20 8:08 AM, Drew Adams wrote: > The message should be one of advice/guidance: > explaining a gotcha, or at least suggesting what > to avoid. That's what the current emacs-27 manual does, or tries to do. If it doesn't do so clearly enough, specific suggestions for improving the wording would be helpful. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 2:36 ` Richard Stallman 2020-04-24 15:08 ` Drew Adams @ 2020-04-24 16:39 ` Mattias Engdegård 2020-04-24 16:46 ` Dmitry Gutov ` (2 more replies) 1 sibling, 3 replies; 170+ messages in thread From: Mattias Engdegård @ 2020-04-24 16:39 UTC (permalink / raw) To: Richard Stallman; +Cc: Michael Heerdegen, ke.vigouroux, eggert, 40671 24 apr. 2020 kl. 04.36 skrev Richard Stallman <rms@gnu.org>: > It seems strange to use the terms "constant" and "mutable" to describe > whether modifying its contents is something you had better avoid. > I think people will find that terminology confusing. Normally > "mutable" means that you CAN change it, not that it is OK to change it. That is an interesting point. What is the difference between CANNOT and SHOULD NOT, operationally? To the user, nothing; there is no gain from disobeying our advice. Implementation-wise, it's whether there are strong checks or not. (For example, in C you should not read from already freed memory, but there is no mechanism actually preventing you from doing so.) It's useful to have the option to add strong checks, so that (setcar '(1 . 2) 3) throws an error. Then, what used to be SHOULD NOT turns into CANNOT, but the attentive user has no reason to change behaviour. Of course the real world is messy and people sometimes have code that breaks the rules but still seem to work. There would need to be a transition period, and a switch to run in a permissive mode. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 16:39 ` Mattias Engdegård @ 2020-04-24 16:46 ` Dmitry Gutov 2020-04-25 2:21 ` Paul Eggert 2020-04-24 17:18 ` Drew Adams 2020-04-25 3:38 ` Richard Stallman 2 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-24 16:46 UTC (permalink / raw) To: Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, eggert, 40671 On 24.04.2020 19:39, Mattias Engdegård wrote: > That is an interesting point. What is the difference between CANNOT and SHOULD NOT, operationally? To the user, nothing; there is no gain from disobeying our advice. The difference is at runtime, obviously. And the problem is using the words in a way that differs from other programming languages, for instance. > It's useful to have the option to add strong checks, so that (setcar '(1 . 2) 3) throws an error. Then, what used to be SHOULD NOT turns into CANNOT, but the attentive user has no reason to change behaviour. *If* we do that, we could call them constants. But I imagine we never will, for backward compatibility reasons. Emacs core itself modifies these "constants" at runtime in quite a few places, I'm sure. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 16:46 ` Dmitry Gutov @ 2020-04-25 2:21 ` Paul Eggert 2020-04-25 2:40 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-25 2:21 UTC (permalink / raw) To: Dmitry Gutov, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 4/24/20 9:46 AM, Dmitry Gutov wrote: > On 24.04.2020 19:39, Mattias Engdegård wrote: >> That is an interesting point. What is the difference between CANNOT and SHOULD >> NOT, operationally? To the user, nothing; there is no gain from disobeying our >> advice. > > The difference is at runtime, obviously. And the problem is using the words in a > way that differs from other programming languages, for instance. That depends on what other programming languages we're talking about. The current use of 'constant' in the manual corresponds reasonably closely to 'const' objects in C and C++. >> It's useful to have the option to add strong checks, so that (setcar '(1 . 2) >> 3) throws an error. Then, what used to be SHOULD NOT turns into CANNOT, but >> the attentive user has no reason to change behaviour. > > *If* we do that, we could call them constants. But I imagine we never will, for > backward compatibility reasons. Emacs core itself modifies these "constants" at > runtime in quite a few places, I'm sure. Actually Emacs formerly was more careful about this sort of thing: more objects were constant and Emacs reliably signaled an error if you tried to change them. If we brought back this feature we'd actually be more backwards-compatible than we already are, at least in some sense. I expect it'd be a good thing to do if it didn't hurt performance, as it should help reliability/safety a bit. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 2:21 ` Paul Eggert @ 2020-04-25 2:40 ` Dmitry Gutov 2020-04-25 3:20 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-25 2:40 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 25.04.2020 05:21, Paul Eggert wrote: > That depends on what other programming languages we're talking about. The > current use of 'constant' in the manual corresponds reasonably closely to > 'const' objects in C and C++. Since we're talking about non-scalar values, do you mean constant pointers to (generally) mutable objects? Or a constant aggregate of mutable objects? When a value is constant in C or C++, you can't change it. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 2:40 ` Dmitry Gutov @ 2020-04-25 3:20 ` Paul Eggert 2020-04-25 19:30 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-25 3:20 UTC (permalink / raw) To: Dmitry Gutov, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 4/24/20 7:40 PM, Dmitry Gutov wrote: >> That depends on what other programming languages we're talking about. The >> current use of 'constant' in the manual corresponds reasonably closely to >> 'const' objects in C and C++. > > Since we're talking about non-scalar values, do you mean constant pointers to > (generally) mutable objects? Or a constant aggregate of mutable objects? Neither. I mean a constant object, e.g., the array of chars denoted by the string literal "abc" in C. > When a value is constant in C or C++, you can't change it. Yes, you can't change it in a portable program, because if you attempt to change it the resulting behavior is undefined. The attempt might succeed so that the "constant" is changed, or you might get a core dump, or you might get an exception, or something else might happen. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 3:20 ` Paul Eggert @ 2020-04-25 19:30 ` Dmitry Gutov 2020-04-26 3:49 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-25 19:30 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 25.04.2020 06:20, Paul Eggert wrote: >> When a value is constant in C or C++, you can't change it. > Yes, you can't change it in a portable program, because if you attempt to change > it the resulting behavior is undefined. The attempt might succeed so that the > "constant" is changed, or you might get a core dump, or you might get an > exception, or something else might happen. Might succeed? Will it even compile? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 19:30 ` Dmitry Gutov @ 2020-04-26 3:49 ` Paul Eggert 2020-04-26 14:03 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-26 3:49 UTC (permalink / raw) To: Dmitry Gutov, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 4/25/20 12:30 PM, Dmitry Gutov wrote: > On 25.04.2020 06:20, Paul Eggert wrote: >>> When a value is constant in C or C++, you can't change it. >> Yes, you can't change it in a portable program, because if you attempt to change >> it the resulting behavior is undefined. The attempt might succeed so that the >> "constant" is changed, or you might get a core dump, or you might get an >> exception, or something else might happen. > > Might succeed? Will it even compile? Yes, although the C/C++ program must type-check and satisfy all other static constraints of course (otherwise it won't compile). Here's a simple example: #include <string.h> int main (void) { return !strcpy ("a", "b"); } This function attempts to modify the "a" string constant, so it might dump core, or might return 0, or might do other things. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 3:49 ` Paul Eggert @ 2020-04-26 14:03 ` Dmitry Gutov 2020-04-26 14:19 ` Eli Zaretskii 2020-04-26 18:57 ` Paul Eggert 0 siblings, 2 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 14:03 UTC (permalink / raw) To: Paul Eggert, Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, 40671 On 26.04.2020 06:49, Paul Eggert wrote: >> Might succeed? Will it even compile? > Yes, although the C/C++ program must type-check and satisfy all other static > constraints of course (otherwise it won't compile). Here's a simple example: > > #include <string.h> > int main (void) { return !strcpy ("a", "b"); } > > This function attempts to modify the "a" string constant, so it might dump core, > or might return 0, or might do other things. g++ string_const.c++ string_const.c++: In function ‘int main()’: string_const.c++:2:35: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings] 2 | int main (void) { return !strcpy ("a", "b"); } I have no idea why it only shows a compile-time warning (probably because of backward-compatibility concerns because in C a string is *not* a const, just a source of undefined behavior), but the warning, at least, is there for the user to see. Not just in the manual. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 14:03 ` Dmitry Gutov @ 2020-04-26 14:19 ` Eli Zaretskii 2020-04-26 14:34 ` Dmitry Gutov 2020-04-26 18:57 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Eli Zaretskii @ 2020-04-26 14:19 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Sun, 26 Apr 2020 17:03:38 +0300 > Cc: Michael Heerdegen <michael_heerdegen@web.de>, ke.vigouroux@laposte.net, > 40671@debbugs.gnu.org > > > #include <string.h> > > int main (void) { return !strcpy ("a", "b"); } > > > > This function attempts to modify the "a" string constant, so it might dump core, > > or might return 0, or might do other things. > > g++ string_const.c++ > string_const.c++: In function ‘int main()’: > string_const.c++:2:35: warning: ISO C++ forbids converting a string > constant to ‘char*’ [-Wwrite-strings] > 2 | int main (void) { return !strcpy ("a", "b"); } Did you try compiling that as a C program, not a C++ program? If I force the C compiler to use -Wwrite-strings, then I get: gcc -Wwrite-strings string_const.c string_const.c: In function 'main': string_const.c:2:35: warning: passing argument 1 of 'strcpy' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] int main (void) { return !strcpy ("a", "b"); } ^~~ In file included from string_const.c:1:0: d:\usr\include\string.h:79:40: note: expected 'char *' but argument is of type 'const char *' _CRTIMP __cdecl __MINGW_NOTHROW char *strcpy (char *, const char *); ^~~~~~ but even that goes away if I modify the program as follows: #include <string.h> int main (void) { return !strcpy ((char *)"a", "b"); } ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 14:19 ` Eli Zaretskii @ 2020-04-26 14:34 ` Dmitry Gutov 2020-04-26 15:46 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 14:34 UTC (permalink / raw) To: Eli Zaretskii Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms On 26.04.2020 17:19, Eli Zaretskii wrote: > Did you try compiling that as a C program, not a C++ program? As C++. From what I understand, in C string literals are not "const", it's just UB to modify them. > but even that goes away if I modify the program as follows: > > #include <string.h> > int main (void) { return !strcpy ((char *)"a", "b"); } If you go out of your way to avoid warnings, then indeed, the compiler won't show them. And typecasts are an easy way to turn compilation errors into runtime errors, in general. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 14:34 ` Dmitry Gutov @ 2020-04-26 15:46 ` Eli Zaretskii 2020-04-26 16:02 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Eli Zaretskii @ 2020-04-26 15:46 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms > Cc: eggert@cs.ucla.edu, mattiase@acm.org, rms@gnu.org, > michael_heerdegen@web.de, ke.vigouroux@laposte.net, 40671@debbugs.gnu.org > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Sun, 26 Apr 2020 17:34:56 +0300 > > > #include <string.h> > > int main (void) { return !strcpy ((char *)"a", "b"); } > > If you go out of your way to avoid warnings, then indeed, the compiler > won't show them. > > And typecasts are an easy way to turn compilation errors into runtime > errors, in general. I think this shows the difference between CANNOT and SHOULD NOT, wrt constants. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 15:46 ` Eli Zaretskii @ 2020-04-26 16:02 ` Dmitry Gutov 2020-04-26 16:58 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 16:02 UTC (permalink / raw) To: Eli Zaretskii Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms On 26.04.2020 18:46, Eli Zaretskii wrote: > I think this shows the difference between CANNOT and SHOULD NOT, wrt > constants. I'm not sure I understand the analogy. Anyway, C and C++ have notoriously tricky semantics in edge cases. It's probably not a good idea to use either of them as example for Emacs Lisp. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 16:02 ` Dmitry Gutov @ 2020-04-26 16:58 ` Eli Zaretskii 2020-04-26 17:39 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Eli Zaretskii @ 2020-04-26 16:58 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms > Cc: ke.vigouroux@laposte.net, eggert@cs.ucla.edu, 40671@debbugs.gnu.org, > michael_heerdegen@web.de, mattiase@acm.org, rms@gnu.org > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Sun, 26 Apr 2020 19:02:05 +0300 > > On 26.04.2020 18:46, Eli Zaretskii wrote: > > I think this shows the difference between CANNOT and SHOULD NOT, wrt > > constants. > > I'm not sure I understand the analogy. That program demonstrates that in C one CAN change a "constant" array. But one definitely SHOULD NOT do that. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 16:58 ` Eli Zaretskii @ 2020-04-26 17:39 ` Dmitry Gutov 2020-04-26 18:14 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 17:39 UTC (permalink / raw) To: Eli Zaretskii Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms On 26.04.2020 19:58, Eli Zaretskii wrote: > That program demonstrates that in C one CAN change a "constant" > array. When you first change it to a "non-constant" one, as far as the compiler is concerned? It's an escape hatch. The same way you "can" funcall a string: int main (void) { return ((int(*) (int))"abc")(1); } It will blow up at runtime, of course. Neither will be the case with "constant" Lisp forms we are talking about. No runtime errors (only subtle, hard to investigate bugs from time to time), and no compilation warnings. The only warnings at all will be in the manual. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 17:39 ` Dmitry Gutov @ 2020-04-26 18:14 ` Eli Zaretskii 2020-04-26 18:32 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Eli Zaretskii @ 2020-04-26 18:14 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms > Cc: ke.vigouroux@laposte.net, eggert@cs.ucla.edu, 40671@debbugs.gnu.org, > michael_heerdegen@web.de, mattiase@acm.org, rms@gnu.org > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Sun, 26 Apr 2020 20:39:38 +0300 > > int main (void) { > return ((int(*) (int))"abc")(1); > } > > It will blow up at runtime, of course. But the previous program will not necessarily blow up at runtime. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 18:14 ` Eli Zaretskii @ 2020-04-26 18:32 ` Dmitry Gutov 2020-04-26 18:41 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 18:32 UTC (permalink / raw) To: Eli Zaretskii Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms On 26.04.2020 21:14, Eli Zaretskii wrote: >> Cc: ke.vigouroux@laposte.net, eggert@cs.ucla.edu, 40671@debbugs.gnu.org, >> michael_heerdegen@web.de, mattiase@acm.org, rms@gnu.org >> From: Dmitry Gutov <dgutov@yandex.ru> >> Date: Sun, 26 Apr 2020 20:39:38 +0300 >> >> int main (void) { >> return ((int(*) (int))"abc")(1); >> } >> >> It will blow up at runtime, of course. > > But the previous program will not necessarily blow up at runtime. "not necessarily" is a damnably low qualifier. My point is, that program is using the same instrument as this one, which *will* blow up at runtime. And the instrument is "making the compiler shut up". ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 18:32 ` Dmitry Gutov @ 2020-04-26 18:41 ` Eli Zaretskii 2020-04-26 18:53 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Eli Zaretskii @ 2020-04-26 18:41 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms > Cc: ke.vigouroux@laposte.net, eggert@cs.ucla.edu, 40671@debbugs.gnu.org, > michael_heerdegen@web.de, mattiase@acm.org, rms@gnu.org > From: Dmitry Gutov <dgutov@yandex.ru> > Date: Sun, 26 Apr 2020 21:32:45 +0300 > > My point is, that program is using the same instrument as this one, > which *will* blow up at runtime. No, it isn't the same instrument. Your program constructs a function call using address that has no valid instructions. Paul's program does nothing like that, it just attempts to write to a data address which may or may not be in write-protected storage. So your program will always blow up, whereas the other one will only blow up if the memory is write-protected. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 18:41 ` Eli Zaretskii @ 2020-04-26 18:53 ` Dmitry Gutov 0 siblings, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 18:53 UTC (permalink / raw) To: Eli Zaretskii Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, rms On 26.04.2020 21:41, Eli Zaretskii wrote: >> Cc: ke.vigouroux@laposte.net, eggert@cs.ucla.edu, 40671@debbugs.gnu.org, >> michael_heerdegen@web.de, mattiase@acm.org, rms@gnu.org >> From: Dmitry Gutov <dgutov@yandex.ru> >> Date: Sun, 26 Apr 2020 21:32:45 +0300 >> >> My point is, that program is using the same instrument as this one, >> which *will* blow up at runtime. > > No, it isn't the same instrument. Your program constructs a function > call using address that has no valid instructions. Paul's program > does nothing like that, it just attempts to write to a data address > which may or may not be in write-protected storage. So your program > will always blow up, whereas the other one will only blow up if the > memory is write-protected. I was imprecise. The program is doing a different thing. But the programmer is using the same instrument in both cases to make it compile. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 14:03 ` Dmitry Gutov 2020-04-26 14:19 ` Eli Zaretskii @ 2020-04-26 18:57 ` Paul Eggert 2020-04-26 19:22 ` Philipp Stephani 2020-04-26 21:23 ` Dmitry Gutov 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-26 18:57 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/26/20 7:03 AM, Dmitry Gutov wrote: > g++ string_const.c++ Ah, my example was C-only. Here is an example for both C and C++: #include <string.h> int main (void) { union { char const *cp; char *p; } u = { "a" }; return !strcpy (u.p, "b"); } This has undefined behavior, and might dump core or might not depending on the implementation. Neither gcc nor g++ issue any warnings in default compilation. Undefined behavior is undesirable and it's not a good thing that Emacs Lisp also has areas that behave like this. Somebody should pry free time to look into fixing them, but that won't be trivial. It appears that portable dumping and other changes have broken some of Emacs's runtime checking in this area. Unfortunately, the relevant code is hairy and any fixes certainly won't happen before the Emacs 27 release. In the meantime it's better to warn users clearly about the gotchas in this area, to help prevent some of the confusion exemplified by Bug#40671. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 18:57 ` Paul Eggert @ 2020-04-26 19:22 ` Philipp Stephani 2020-04-26 20:14 ` Paul Eggert 2020-04-26 21:23 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Philipp Stephani @ 2020-04-26 19:22 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Dmitry Gutov, Richard Stallman Am So., 26. Apr. 2020 um 20:58 Uhr schrieb Paul Eggert <eggert@cs.ucla.edu>: > > On 4/26/20 7:03 AM, Dmitry Gutov wrote: > > g++ string_const.c++ > > Ah, my example was C-only. Here is an example for both C and C++: > > #include <string.h> > int main (void) { > union { char const *cp; char *p; } u = { "a" }; > return !strcpy (u.p, "b"); > } > > This has undefined behavior, and might dump core or might not depending on the > implementation. Neither gcc nor g++ issue any warnings in default compilation. Yes, but nobody "accidentally" writes code like this. OTOH, code like attempting to mutate a "constant" Lisp object seems trivial to write accidentally. > > Undefined behavior is undesirable and it's not a good thing that Emacs Lisp also > has areas that behave like this. Somebody should pry free time to look into > fixing them, but that won't be trivial. What would be needed? We could either (a) remove the notion of "constant" objects so that all objects become mutable, (b) introduce static type checking including const-correctness so that attempting to mutate a "constant" object would fail byte-compilation, and/or (c) make it an error to mutate such objects at runtime (similar to (set t nil)). ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 19:22 ` Philipp Stephani @ 2020-04-26 20:14 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-26 20:14 UTC (permalink / raw) To: Philipp Stephani Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Dmitry Gutov, Richard Stallman On 4/26/20 12:22 PM, Philipp Stephani wrote: > nobody "accidentally" writes code like this. Not code like my trivial example, no. But the underlying problem is all too common. After all, it's why Emacs is dumping core here - the Emacs Lisp interpreter is using C code like that to implement some Lisp strings. > We could either (a) remove the notion of > "constant" objects so that all objects become mutable, (b) introduce > static type checking including const-correctness so that attempting to > mutate a "constant" object would fail byte-compilation, and/or (c) > make it an error to mutate such objects at runtime (similar to (set t > nil)). Neither (a) nor (b) sound very practical. Emacs formerly did a better job at (c) and could do so again, so it's an obvious way to move forward here. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 18:57 ` Paul Eggert 2020-04-26 19:22 ` Philipp Stephani @ 2020-04-26 21:23 ` Dmitry Gutov 2020-04-26 23:13 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-26 21:23 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 26.04.2020 21:57, Paul Eggert wrote: > On 4/26/20 7:03 AM, Dmitry Gutov wrote: >> g++ string_const.c++ > > Ah, my example was C-only. Here is an example for both C and C++: > > #include <string.h> > int main (void) { > union { char const *cp; char *p; } u = { "a" }; > return !strcpy (u.p, "b"); > } > > This has undefined behavior, and might dump core or might not depending on the > implementation. Neither gcc nor g++ issue any warnings in default compilation. This just illustrates a weakness of type system in C/C++. The same way you could pass a string into a function that expects an int. > Undefined behavior is undesirable and it's not a good thing that Emacs Lisp also > has areas that behave like this. But is it undefined? I think it's well-defined and predictable, though it's harder to make sense of that we would like. > Somebody should pry free time to look into > fixing them, but that won't be trivial. It appears that portable dumping and > other changes have broken some of Emacs's runtime checking in this area. Do you have an example of a version of Emacs where this behavior was different? > Unfortunately, the relevant code is hairy and any fixes certainly won't happen > before the Emacs 27 release. In the meantime it's better to warn users clearly > about the gotchas in this area, to help prevent some of the confusion > exemplified by Bug#40671. Perhaps you meant some other bug report? This is the one we're commenting on. My concern here is the terms. I worry that someday someone will come report a problem, and we respond with "this syntax creates constant values, please take care not to modify them". Then that someone will go away with very low opinion of our mental faculties. In all of my experience, the term "constant" is usually applied to names (variables), or pointers. And it almost always means that you're not allowed to change it. Or if you are, you can't do it by accident. The closest term that applies to values, I think, is "immutable". But those are definitely protected from modification. For our situation, the term "constant reference" comes to mind, but I don't know exactly how to rephrase the manual best. The previous term "literal objects", however, seems accurate enough, and if the "constant-ness" is going to live only in the manual anyway, perhaps we should just say "please don't modify literal objects [unless you really know what you're doing]". ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 21:23 ` Dmitry Gutov @ 2020-04-26 23:13 ` Paul Eggert 2020-04-27 0:53 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-26 23:13 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/26/20 2:23 PM, Dmitry Gutov wrote: > This just illustrates a weakness of type system in C/C++. The same way you could > pass a string into a function that expects an int. Although it's a weakness, it's different from the char * vs int weakness. It's well-defined in C that one can cast char * to char const * and back without trouble. The same is not true for casting char * to int and back. > is it undefined? Yes, it's undefined. C11 section 6.7.3 paragraph 6 says, "If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined." > Do you have an example of a version of Emacs where this behavior was different? Emacs 26. >> Unfortunately, the relevant code is hairy and any fixes certainly won't happen >> before the Emacs 27 release. In the meantime it's better to warn users clearly >> about the gotchas in this area, to help prevent some of the confusion >> exemplified by Bug#40671. > > Perhaps you meant some other bug report? No, the original bug report that started this thread illustrates some of the confusion in this area. > In all of my experience, the term "constant" is usually applied to names > (variables), or pointers. And it almost always means that you're not allowed to > change it. Or if you are, you can't do it by accident. Unfortunately that experience does not apply to C and to other low-level languages. Even Java once allowed programs to modify "constants" by using reflection, though recent Java versions have fixed this. > The previous term "literal objects", however, seems accurate enough We could use any term we like, and if there's consensus for using the term "literal object" instead of "constant" then we can redo the manual that way. However, the problem can occur with strings that were never string literals in any source-code Elisp program. And a Elisp string can begin its life as a mutable string and then become a "constant" (or "literal object") later. So it's not clear that the longer phrase is less confusing. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-26 23:13 ` Paul Eggert @ 2020-04-27 0:53 ` Dmitry Gutov 2020-04-27 1:49 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-27 0:53 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 27.04.2020 02:13, Paul Eggert wrote: >> This just illustrates a weakness of type system in C/C++. The same way you could >> pass a string into a function that expects an int. > > Although it's a weakness, it's different from the char * vs int weakness. It's > well-defined in C that one can cast char * to char const * and back without > trouble. The same is not true for casting char * to int and back. This compiles fine: #include <string.h> int main (void) { return !strcpy ((char*)2, "b"); } My point is, it's hard to discuss static typing guarantees when type casting is involved. >> is it undefined? > > Yes, it's undefined. C11 section 6.7.3 paragraph 6 says, "If an attempt is made > to modify an object defined with a const-qualified type through use of an lvalue > with non-const-qualified type, the behavior is undefined." Sorry if that was unclear. I mean, is the behavior of "literal objects" in Emacs Lisp undefined when one tries to modify them? >> Do you have an example of a version of Emacs where this behavior was different? > > Emacs 26. Sorry, I don't have an Emacs 26 at hand. Should 25 suffice? Just tried this in IELM: ELISP> (setq a '(1 . 2)) (1 . 2) ELISP> (setcdr a 3) 3 (#o3, #x3, ?\C-c) ELISP> a (1 . 3) ELISP> emacs-version "25.2.3" >>> Unfortunately, the relevant code is hairy and any fixes certainly won't happen >>> before the Emacs 27 release. In the meantime it's better to warn users clearly >>> about the gotchas in this area, to help prevent some of the confusion >>> exemplified by Bug#40671. >> >> Perhaps you meant some other bug report? > > No, the original bug report that started this thread illustrates some of the > confusion in this area. Okay, yes. I though you had a bug report with a description of a practical problem. >> In all of my experience, the term "constant" is usually applied to names >> (variables), or pointers. And it almost always means that you're not allowed to >> change it. Or if you are, you can't do it by accident. > > Unfortunately that experience does not apply to C and to other low-level > languages. Even Java once allowed programs to modify "constants" by using > reflection, though recent Java versions have fixed this. Hence the last sentence of my paragraph you quoted. In Ruby, we also have "constants" and we sometimes laugh about being able to change them. And yet, there also you can't do it by accident. >> The previous term "literal objects", however, seems accurate enough > > We could use any term we like, and if there's consensus for using the term > "literal object" instead of "constant" then we can redo the manual that way. > However, the problem can occur with strings that were never string literals in > any source-code Elisp program. And a Elisp string can begin its life as a > mutable string and then become a "constant" (or "literal object") later. So it's > not clear that the longer phrase is less confusing. "A mutable string can become a constant later and yet remain modifiable in practice" sounds really confusing. We better warn against modifying any values that are part of a "literal object" anywhere. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-27 0:53 ` Dmitry Gutov @ 2020-04-27 1:49 ` Paul Eggert 2020-04-28 3:05 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-27 1:49 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/26/20 5:53 PM, Dmitry Gutov wrote: > is the behavior of "literal objects" in Emacs > Lisp undefined when one tries to modify them? Yes. >>> Do you have an example of a version of Emacs where this behavior was different? >> >> Emacs 26. > > Sorry, I don't have an Emacs 26 at hand. Should 25 suffice? Yes. Just tried this in > IELM: > > ELISP> (setq a '(1 . 2)) > (1 . 2) > > ELISP> (setcdr a 3) > 3 (#o3, #x3, ?\C-c) > ELISP> a > (1 . 3) Yes, the behavior is undefined in Emacs 25 too. Undefined means that the behavior you describe is allowed - in this instance you modified the "constant" and got away with it. > In Ruby, we also have "constants" and we sometimes laugh about being able to > change them. And yet, there also you can't do it by accident. I suppose it depends on what one means by "accident". :-) Perhaps we could agree that accidents, whatever they are, happen more often in C.... > We better warn against modifying any values that are part of a "literal object" > anywhere. That's what the emacs-27 doc does, or at least tries to do. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-27 1:49 ` Paul Eggert @ 2020-04-28 3:05 ` Dmitry Gutov 2020-04-28 8:17 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 3:05 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 27.04.2020 04:49, Paul Eggert wrote: >> Sorry, I don't have an Emacs 26 at hand. Should 25 suffice? > > Yes. > > Just tried this in >> IELM: >> >> ELISP> (setq a '(1 . 2)) >> (1 . 2) >> >> ELISP> (setcdr a 3) >> 3 (#o3, #x3, ?\C-c) >> ELISP> a >> (1 . 3) > > Yes, the behavior is undefined in Emacs 25 too. Undefined means that the > behavior you describe is allowed - in this instance you modified the "constant" > and got away with it. I'm not sure which problematic cases you mean, then. Ones related to pure space? >> In Ruby, we also have "constants" and we sometimes laugh about being able to >> change them. And yet, there also you can't do it by accident. > > I suppose it depends on what one means by "accident". :-) Perhaps we could agree > that accidents, whatever they are, happen more often in C.... It feels like you're just side-stepping the arguments, one after another. >> We better warn against modifying any values that are part of a "literal object" >> anywhere. > > That's what the emacs-27 doc does, or at least tries to do. I wish it did that without inventing new meanings for the words "constant" and "mutable". It will only breed confusion. Take this paragraph: Although all numbers are constants and all markers are mutable, some types contain both constant and mutable members. These types include conses, vectors, strings, and symbols. For example, the string literal @code{"aaa"} yields a constant string, whereas the function call @code{(make-string 3 ?a)} yields a mutable string that can be changed via later calls to @code{aset}. It makes one think that 'aset' can't be called on "aaa". That it will either fail to change the value, or signal an error. Whereas the result is that the value is changed, no errors or warnings. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 3:05 ` Dmitry Gutov @ 2020-04-28 8:17 ` Paul Eggert 2020-04-28 13:54 ` Dmitry Gutov 2020-04-28 17:25 ` Drew Adams 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-28 8:17 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/27/20 8:05 PM, Dmitry Gutov wrote: > I'm not sure which problematic cases you mean, then. Ones related to pure space? That's one issue. Earlier versions of Emacs also had trouble if you modified list structures while executing them. I've squashed some of those issues more recently but would not be surprised if some remain. I don't know how much optimization the byte compiler did in earlier versions, but if it did anything like what it does now, that's also a source of problems. > Although all numbers are constants and all markers are > mutable, some types contain both constant and mutable members. These > types include conses, vectors, strings, and symbols. For example, the > string > literal @code{"aaa"} yields a constant string, whereas the function > call @code{(make-string 3 ?a)} yields a mutable string that can be > changed via later calls to @code{aset}. > > It makes one think that 'aset' can't be called on "aaa". That it will either > fail to change the value, or signal an error. Whereas the result is that the > value is changed, no errors or warnings. 'aset' *shouldn't* be called on "aaa". We could replace "a constant string" with "a constant string that should not be changed"; would that help? > It feels like you're just side-stepping the arguments, one after another. There's certainly no intent to side-step. And I don't sense that there's really much disagreement here: we both agree that the current behavior is unfortunate, the major point of disagreement is about terminology in the documentation. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 8:17 ` Paul Eggert @ 2020-04-28 13:54 ` Dmitry Gutov 2020-04-28 17:59 ` Paul Eggert 2020-04-28 17:25 ` Drew Adams 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 13:54 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 28.04.2020 11:17, Paul Eggert wrote: > On 4/27/20 8:05 PM, Dmitry Gutov wrote: > >> I'm not sure which problematic cases you mean, then. Ones related to pure space? > > That's one issue. Earlier versions of Emacs also had trouble if you modified > list structures while executing them. I've squashed some of those issues more > recently but would not be surprised if some remain. If any led to segfaults, they have to be fixed in the code anyway. > I don't know how much optimization the byte compiler did in earlier versions, > but if it did anything like what it does now, that's also a source of problems. Well, here's a damning example. And it doesn't involve the byte compiler: ELISP> (defun abc () "abc") abc ELISP> (aset (abc) 0 ?b) 98 (#o142, #x62, ?b) ELISP> (abc) "bbc" I wonder how other Lisps deal with that. The Ruby interpreter, from the first release I think, always created copies of the literals when a method was called. Exactly to avoid this kind of broken semantics. In the recent versions, they added a pragma string (to be added to the top of the file) that makes all such literals in that file "immutable". That means that any attempt to change them errors at runtime. And now it's considered good style to use that pragma everywhere. >> Although all numbers are constants and all markers are >> mutable, some types contain both constant and mutable members. These >> types include conses, vectors, strings, and symbols. For example, the >> string >> literal @code{"aaa"} yields a constant string, whereas the function >> call @code{(make-string 3 ?a)} yields a mutable string that can be >> changed via later calls to @code{aset}. >> >> It makes one think that 'aset' can't be called on "aaa". That it will either >> fail to change the value, or signal an error. Whereas the result is that the >> value is changed, no errors or warnings. > > 'aset' *shouldn't* be called on "aaa". Indeed it shouldn't. > We could replace "a constant string" with "a constant string that should not be > changed"; would that help? That sounds like a weird tautological non-advice. It shouldn't be changed because it's a value of a string literal. Not because it's constant (it isn't). >> It feels like you're just side-stepping the arguments, one after another. > > There's certainly no intent to side-step. And I don't sense that there's really > much disagreement here: we both agree that the current behavior is unfortunate, > the major point of disagreement is about terminology in the documentation. From the outset all arguments were about the terminology. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 13:54 ` Dmitry Gutov @ 2020-04-28 17:59 ` Paul Eggert 2020-04-28 18:46 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-28 17:59 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 6:54 AM, Dmitry Gutov wrote: > It shouldn't be changed because it's a value of a string literal. Not because > it's constant (it isn't). That depends on the string literal and the particular Emacs implementation. In Emacs master, some string literals yield strings that are constant because Emacs has undefined behavior at the C level (maybe coredump, maybe not) if you try to change them, some string literals are constant because if you try to change them Emacs will reliably signal an error, some string literals are constant because if you change them Emacs might behave unpredictably without having undefined behavior at the C level, and the remaining string literals are constant becase you shouldn't change them. We have never documented exactly which string literals are which, and we shouldn't document that now because it is an implementation detail that users should not rely upon. It would be a mistake for the documentation to say that the problems we've been discussing occur only with string literals, as these problems can occur for strings that were not generated from string literals, and they can also occur for objects that are not strings. So "string literal" would be the wrong terminology here. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 17:59 ` Paul Eggert @ 2020-04-28 18:46 ` Dmitry Gutov 2020-04-28 19:20 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 18:46 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 28.04.2020 20:59, Paul Eggert wrote: > On 4/28/20 6:54 AM, Dmitry Gutov wrote: >> It shouldn't be changed because it's a value of a string literal. Not because >> it's constant (it isn't). > > That depends on the string literal and the particular Emacs implementation. In > Emacs master, some string literals yield strings that are constant because Emacs > has undefined behavior at the C level (maybe coredump, maybe not) That sounds like something we have to fix. Emacs shouldn't dump core no matter what Lisp code the user wrote. Unless it leads to an OOM, I guess. > if you try to > change them, some string literals are constant because if you try to change them > Emacs will reliably signal an error, some string literals are constant because > if you change them Emacs might behave unpredictably without having undefined > behavior at the C level, and the remaining string literals are constant becase > you shouldn't change them. That's not a constant, that's an eldritch abomination. Some unknown, unpredictable thing. Which is generally bad for language semantics and for its users. I understand why it's hard to fix that, but co-opting common words to mean different things is bad. Using semantics that might be "slightly familiar" only to grizzled C programmers is also bad. If you really want to have an adjective for such values, either ask some language theorist or make up one (and I'm only half-kidding here). Example: Some values in Emacs are constant, meaning you can't change them (e.g. you can't change an integer), and some are mutable (e.g. a cons cell is easy to change). There is a particular kind of values called fizzleworp (see {String literals}, {Quote} and {Backquote}), which are dangerous to modify. Please take care not to do that in your code. <... some enumeration of situation which create fizzleworp values or make an existing value fizzleworp ...> OR Anyplace we introduce literals in the manual, if they are dangerous to modify, we say that. Without inventing new words. > We have never documented exactly which string > literals are which, and we shouldn't document that now because it is an > implementation detail that users should not rely upon. No argument here. > It would be a mistake for the documentation to say that the problems we've been > discussing occur only with string literals, as these problems can occur for > strings that were not generated from string literals, and they can also occur > for objects that are not strings. So "string literal" would be the wrong > terminology here. String literals, Lisp form literals, and any members of such forms. I might be forgetting something, but this list is not too long, is it? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 18:46 ` Dmitry Gutov @ 2020-04-28 19:20 ` Paul Eggert 2020-04-28 19:33 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-28 19:20 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 11:46 AM, Dmitry Gutov wrote: > That sounds like something we have to fix. Yes, absolutely, though we can't feasibly do that before the next release. > That's not a constant, that's an eldritch abomination. I say "constant", you say "eldritch". :-) > Using semantics that might be "slightly familiar" > only to grizzled C programmers is also bad. It's not just "slightly familiar" to grizzled C/C++/etc. programmers. It's a concept that's pretty much part of their daily lives. > There is a particular kind of values called fizzleworp (see {String literals}, {Quote} and {Backquote}), which are dangerous to modify. Let's not go that route. It'd be overdocumenting internal details that are not generally known. I don't know all the details, so I couldn't write all that documentation without a lot of nontrivial investigation. And these details are likely to change so users should not rely on them anyway. Instead of going out into the wilderness and tagging and identifying each dragon and its lair, the documentation should keep things simple and merely say "there are dragons out in the wilderness; you shouldn't go there". This is much simpler and easier to understand and maintain, and is safer overall. > Lisp form literals, and any members of such forms. I might be forgetting something, but this list is not too long, is it? Yes the list isn't *that* long, and it's in the documentation already - as long as we are willing to put up with a conservative list (e.g., you shouldn't modify anything in the list) rather than insisting on an exhaustive list (e.g., here's what happens if you try to modify X, here's what happens if you try to modify Y, etc.). ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 19:20 ` Paul Eggert @ 2020-04-28 19:33 ` Dmitry Gutov 2020-04-28 20:09 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 19:33 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 28.04.2020 22:20, Paul Eggert wrote: > On 4/28/20 11:46 AM, Dmitry Gutov wrote: > >> That sounds like something we have to fix. > > Yes, absolutely, though we can't feasibly do that before the next release. Yeah, ok. >> That's not a constant, that's an eldritch abomination. > > I say "constant", you say "eldritch". :-) And then I explain why "constant" is bad, multiple times. With examples from other languages. >> Using semantics that might be "slightly familiar" >> only to grizzled C programmers is also bad. > > It's not just "slightly familiar" to grizzled C/C++/etc. programmers. It's a > concept that's pretty much part of their daily lives. You take the concept of "constant values", look it up in the C standard (where modifying a constant is "undefined behavior") and then make a conclusion that if modifying something is "undefined behavior", it must be called a constant. Outside of C standard, to boot. Emacs users are not C programmers. >> There is a particular kind of values called fizzleworp (see {String literals}, {Quote} and {Backquote}), which are dangerous to modify. > > Let's not go that route. It'd be overdocumenting internal details that are not > generally known. I don't know all the details, so I couldn't write all that > documentation without a lot of nontrivial investigation. And these details are > likely to change so users should not rely on them anyway. That's not what I was suggesting. I gave an example on using the words, not on which cases to enumerate. > Instead of going out into the wilderness and tagging and identifying each dragon > and its lair, the documentation should keep things simple and merely say "there > are dragons out in the wilderness; you shouldn't go there". This is much simpler > and easier to understand and maintain, and is safer overall. The map still has to circle the wilderness on the map somehow. >> Lisp form literals, and any members of such forms. I might be forgetting something, but this list is not too long, is it? > > Yes the list isn't *that* long, and it's in the documentation already - as long > as we are willing to put up with a conservative list (e.g., you shouldn't modify > anything in the list) rather than insisting on an exhaustive list (e.g., here's > what happens if you try to modify X, here's what happens if you try to modify Y, > etc.). Conservative list is fine, as long as we don't use the word "constant". ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 19:33 ` Dmitry Gutov @ 2020-04-28 20:09 ` Paul Eggert 2020-04-28 21:10 ` Dmitry Gutov 2020-04-28 21:18 ` Dmitry Gutov 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-28 20:09 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 12:33 PM, Dmitry Gutov wrote: > And then I explain why "constant" is bad, multiple times. With examples from > other languages. The word "constant" means different things in different programming languages. The meaning used in the Elisp manual is reasonably close to its meaning in C/C++/Fortran/Common Lisp/etc., and that describes how Emacs behaves now. We'd prefer it if Emacs behaved more like what Python does with its immutable objects, and some day we should change Emacs to do that. When we do so, we can modify the Elisp manual accordingly. In the meantime we need to document what we have. > Emacs users are not C programmers. Of course not, but this area needs documentation and when the Emacs concept is similar to an already-existing one in C/C++/etc. it's not necessarily a bad thing to adopt their terminology and/or notation, even if that terminology/notation happens to mean something else in other contexts. >>> There is a particular kind of values called fizzleworp (see {String >>> literals}, {Quote} and {Backquote}), which are dangerous to modify. >> >> Let's not go that route. It'd be overdocumenting internal details that are not >> generally known. I don't know all the details, so I couldn't write all that >> documentation without a lot of nontrivial investigation. And these details are >> likely to change so users should not rely on them anyway. > > That's not what I was suggesting. I gave an example on using the words, not on > which cases to enumerate. Then I don't understand your suggestion. I thought you were saying that we should distinguish among the types of constants and should say what happens when you modify each type. The manual already does this to a very limited extent, and I thought you were suggesting that it should do a reasonably exhaustive job of it, in order to greatly limit the area where Emacs behavior is undefined. I'd rather not go that route generally, for the reasons stated above. That being said, it might make sense to make some changes in this area. Or perhaps I'm still misunderstanding you, in which case further clarification would be helpful. A simple way to be clear in this area is to propose specific wording changes, preferably in git format-patch form. It's not enough to say "I don't like the word 'constant'." > The map still has to circle the wilderness on the map somehow. Yes, and the documentation does that now. The edge of the wild is the line between constants and non-constants. A program that tries to modify a constant is out in the wilderness. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 20:09 ` Paul Eggert @ 2020-04-28 21:10 ` Dmitry Gutov 2020-04-28 23:10 ` Paul Eggert 2020-04-28 21:18 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 21:10 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 28.04.2020 23:09, Paul Eggert wrote: > The word "constant" means different things in different programming languages. > The meaning used in the Elisp manual is reasonably close to its meaning in > C/C++/Fortran/Common Lisp/etc., and that describes how Emacs behaves now. As we've pointed out, Elisp is a wildly different beast from C. Static vs. dynamic, etcetera. > Of course not, but this area needs documentation and when the Emacs concept is > similar to an already-existing one in C/C++/etc. Not really. > Then I don't understand your suggestion. > > I thought you were saying that we should distinguish among the types of > constants and should say what happens when you modify each type. Which part of my example contained the "what happens when"? > A simple way to be clear in this area is to propose specific wording changes, > preferably in git format-patch form. It's not enough to say "I don't like the > word 'constant'." Could you first provide the list of your commits that changed the manual pertaining to this discussion? Then I'll at least know what to try to change. > Yes, and the documentation does that now. The edge of the wild is the line > between constants and non-constants. Write that line between fizzleworp and non-fizzleworp values. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 21:10 ` Dmitry Gutov @ 2020-04-28 23:10 ` Paul Eggert 2020-04-28 23:36 ` Dmitry Gutov ` (2 more replies) 0 siblings, 3 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-28 23:10 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 2:10 PM, Dmitry Gutov wrote: > On 28.04.2020 23:09, Paul Eggert wrote: >> The meaning used in the Elisp manual is reasonably close to its meaning in >> C/C++/Fortran/Common Lisp/etc., and that describes how Emacs behaves now. > > As we've pointed out, Elisp is a wildly different beast from C. And Elisp is also wildly different from Common Lisp, for some interpretation of "wildly different". But it's close enough in this area. I don't see why we should depart from terminology used by C/C++/Fortran/Common Lisp/etc.; it's reasonably well-established. >> I thought you were saying that we should distinguish among the types of >> constants and should say what happens when you modify each type. > Among the types of mutable values. Between the "normal" and "do not touch" ones. The "do not touch" values are called "constants" in the documentation now, just as they are in the documentation for the other languages. I don't see why values that should not change should be called "mutable". And even if we called these values "mutable", I don't see why the documentation should distinguish among the various types of "mutable" values that should not change. The whole area is messy and differs from release to release and from platform to platform. Programs should not change values-that-should-not-change and we shouldn't try to catalog what happens if programs do what they shouldn't, since it's complicated and we often don't even know what'll happen. Generally speaking, the Elisp documentation should just say "you shouldn't change these objects", like it does for C/C++/etc. > Could you first provide the list of your commits that changed the manual > pertaining to this discussion? You can run this shell command in the emacs-27 branch. git log --author=eggert --since='Apr 18 12:59:17 2020 -0700' > Write that line between fizzleworp and non-fizzleworp values. I don't understand this remark. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:10 ` Paul Eggert @ 2020-04-28 23:36 ` Dmitry Gutov 2020-04-28 23:53 ` Paul Eggert 2020-04-28 23:53 ` Dmitry Gutov 2020-04-29 0:55 ` Drew Adams 2 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 23:36 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 02:10, Paul Eggert wrote: > The "do not touch" values are called "constants" in the documentation now, just > as they are in the documentation for the other languages. In other languages, constants are something you can't change. > I don't see why values > that should not change should be called "mutable". Mutable values are ones the user _can_ change. It's a structural thing. > And even if we called these values "mutable", I don't see why the documentation > should distinguish among the various types of "mutable" values that should not > change. Because the user sees strings and conses in both cases. All mutable values, and yet changing some of them is a bad idea (even though Emacs will most likely let you). > Generally speaking, the Elisp documentation should just say "you shouldn't > change these objects", like it does for C/C++/etc. Do you see me arguing against that? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:36 ` Dmitry Gutov @ 2020-04-28 23:53 ` Paul Eggert 2020-04-28 23:57 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-28 23:53 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 4:36 PM, Dmitry Gutov wrote: > On 29.04.2020 02:10, Paul Eggert wrote: >> The "do not touch" values are called "constants" in the documentation now, just >> as they are in the documentation for the other languages. > > In other languages, constants are something you can't change. That's not true for C, or for Common Lisp, or for the other languages I mentioned. You can change constants sometimes and not others. Behavior is undefined if you try. It sounds like we're merely disagreeing about using the word "constant" vs using some other word or phrase (it's not clear what). But there's clear precedent elsewhere for the terminology now in use in the emacs-27 manual. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:53 ` Paul Eggert @ 2020-04-28 23:57 ` Dmitry Gutov 0 siblings, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 23:57 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 02:53, Paul Eggert wrote: > It sounds like we're merely disagreeing about using the word "constant" vs using > some other word or phrase (it's not clear what). I gave a couple of options. > But there's clear precedent > elsewhere for the terminology now in use in the emacs-27 manual. Any particular example? Before your latest changes, I mean. Please don't say 'defconst'. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:10 ` Paul Eggert 2020-04-28 23:36 ` Dmitry Gutov @ 2020-04-28 23:53 ` Dmitry Gutov 2020-04-29 0:04 ` Paul Eggert 2020-04-29 0:55 ` Drew Adams 2 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 23:53 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 02:10, Paul Eggert wrote: > terminology used by C/C++/Fortran Quote from https://en.cppreference.com/w/cpp/language/cv: const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object _cannot_ be modified: attempt to do so directly is a _compile-time error_, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior. Emphasis mine. I'll take a look at the commit, thanks. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:53 ` Dmitry Gutov @ 2020-04-29 0:04 ` Paul Eggert 2020-04-29 0:14 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-29 0:04 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 4:53 PM, Dmitry Gutov wrote: > const object - an object whose type is const-qualified, or a non-mutable > subobject of a const object. Such object _cannot_ be modified: attempt to do so > directly is a _compile-time error_, and attempt to do so indirectly (e.g., by > modifying the const object through a reference or pointer to non-const type) > results in undefined behavior. It's reasonable to have compile-time checking in a statically-typed language, though (as the above quote notes) the checking isn't adequate for C++ and one can get undefined behavior anyway in that language. And we could add some similar compile-time checking for the Elisp byte-compiler: it could warn about misuses like (aset "abc" 0 ?d), for example. However, any such compile-time checking would be either too restrictive (with false positives) or only partial (with false negatives) or both (as in C++). So it wouldn't be an adequate substitute for documenting that some objects should not be changed. > I gave a couple of options. I recall your using "literal object" but that's not a good choice of wording because the problem can occur with objects that are not literally present in any source code. >> there's clear precedent >> elsewhere for the terminology now in use in the emacs-27 manual. > > Any particular example? By "elsewhere" I meant in other language documentation (C/C++/etc.), not elsewhere in the emacs-27 manual. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 0:04 ` Paul Eggert @ 2020-04-29 0:14 ` Dmitry Gutov 0 siblings, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-04-29 0:14 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 03:04, Paul Eggert wrote: > It's reasonable to have compile-time checking in a statically-typed language, > though (as the above quote notes) the checking isn't adequate for C++ and one > can get undefined behavior anyway in that language. All the undefined-behavior stuff in the language is part of backward compatibility with C. Like I said, the same argument that says "you can change a const in C++" also says "string and int and void are basically the same type". > And we could add some > similar compile-time checking for the Elisp byte-compiler: it could warn about > misuses like (aset "abc" 0 ?d), for example. Not the worst idea. Won't work: it's a dynamic language. Hence the example of how a similar problem was dealt with in a fellow dynamic language that I wrote about a couple of messages ago. > However, any such compile-time checking would be either too restrictive (with > false positives) The "too restrictive" end of the spectrum will result in prohibiting the user from modifying any and all conses. > or only partial (with false negatives) or both (as in C++). So > it wouldn't be an adequate substitute for documenting that some objects should > not be changed. With runtime checks, it could. But that might be too costly. > I recall your using "literal object" but that's not a good choice of wording > because the problem can occur with objects that are not literally present in any > source code. "Any object that is part of a literal value". You can probably extend that sentence to be exhaustive. > By "elsewhere" I meant in other language documentation (C/C++/etc.), not > elsewhere in the emacs-27 manual. In "etc", you mentioned Common Lisp previously. Any idea how it deals with that problem? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 23:10 ` Paul Eggert 2020-04-28 23:36 ` Dmitry Gutov 2020-04-28 23:53 ` Dmitry Gutov @ 2020-04-29 0:55 ` Drew Adams 2020-04-29 1:03 ` Dmitry Gutov 2020-04-29 1:38 ` Paul Eggert 2 siblings, 2 replies; 170+ messages in thread From: Drew Adams @ 2020-04-29 0:55 UTC (permalink / raw) To: Paul Eggert, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > I don't see why we should depart from terminology used by > C/C++/Fortran/Common Lisp/etc.; it's reasonably well-established. You're _not_ using the language that's used for Common Lisp. I echoed what the CL doc said. Elisp corresponds to the behavior of CLTL1 in this regard, not to any later update that makes the interpreter behave more like compiled code (raising an error in both). Like CLTL1, we should just warn about the gotcha, not say that it's about modification or attempted modification of "constants". A few mails ago, you wondered if the disagreement has been only about terminology. And the response was mostly "Yes" - objections to your use of "mutable" and "constant"/"immutable", and your use of "cannot" instead of "should not" (aka "Don't"). You've since ignored that response, it seems. This has dragged on, just circling. I, for one, give up. But I do hope you'll listen to others. And yes, Michael's point about committing before discussing & deciding is spot on too. Remember your curly-quote crusade? You did the same thing then, with similar complaints about acting widely, unilaterally, and prematurely. My suggestion is to see how people have already warned users about this gotcha here & there (forums etc.) and do likewise. Come to an agreement about the behavior to warn users about - in practical, operational, but not exhaustive, terms. A simple quoted-list example is enough, along with a general description. Once there's agreement about the message, including any example(s), the wording will fall out naturally. (At least the wording won't be a battleground, once the message is decided on.) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 0:55 ` Drew Adams @ 2020-04-29 1:03 ` Dmitry Gutov 2020-04-29 1:15 ` Drew Adams 2020-04-29 1:38 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-04-29 1:03 UTC (permalink / raw) To: Drew Adams, Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 03:55, Drew Adams wrote: > But I do hope you'll listen to others. And yes, > Michael's point about committing before discussing > & deciding is spot on too. Remember your curly-quote > crusade? You did the same thing then, with similar > complaints about acting widely, unilaterally, and > prematurely. I disagree about the comparison. The curly-quote was (still is) a fiasco, a big scope of changes (and breakages) with comparatively little practical benefit. This bug report at least deals with a real problem. And of course it's much easier to criticize (what a lot of us have been doing) than provide actual wording changes. So I wouldn't say committing too soon was a significant problem in this particular instance. It's not a far-reaching change, and we could still revert it. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 1:03 ` Dmitry Gutov @ 2020-04-29 1:15 ` Drew Adams 2020-04-29 1:27 ` Michael Heerdegen 0 siblings, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-29 1:15 UTC (permalink / raw) To: Dmitry Gutov, Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > > Remember your curly-quote > > crusade? You did the same thing then, with similar > > complaints about acting widely, unilaterally, and > > prematurely. > > I disagree about the comparison. The curly-quote was (still is) a > fiasco, a big scope of changes (and breakages) with comparatively > little practical benefit. This bug report at least deals with a > real problem. Yes, I agree about that difference. > And of course it's much easier to criticize (what a lot of us have been > doing) than provide actual wording changes. So I wouldn't say > committing too soon was a significant problem in this particular > instance. It's not a far-reaching change, and we could still revert it. And I agree with you there, too. But I think Michael's point was about the cooperation/attitude, not the nature or difficulty of the problem to solve or the magnitude of any problem of undoing committed changes. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 1:15 ` Drew Adams @ 2020-04-29 1:27 ` Michael Heerdegen 0 siblings, 0 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-04-29 1:27 UTC (permalink / raw) To: Drew Adams Cc: ke.vigouroux, Paul Eggert, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Drew Adams <drew.adams@oracle.com> writes: > But I think Michael's point was about the cooperation/attitude, not > the nature or difficulty of the problem to solve or the magnitude of > any problem of undoing committed changes. Yes, I was referring to Paul's complaints and frustration, and I wondered why the discussion developed like that. Maybe I'm totally wrong, it's just how I experienced things. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 0:55 ` Drew Adams 2020-04-29 1:03 ` Dmitry Gutov @ 2020-04-29 1:38 ` Paul Eggert 2020-04-29 4:36 ` Drew Adams 2020-05-01 3:13 ` Dmitry Gutov 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-29 1:38 UTC (permalink / raw) To: Drew Adams, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 5:55 PM, Drew Adams wrote: > You're _not_ using the language that's used for Common Lisp. In what sense does the language differ? Here's a quote from CLtL2 (page 115): "it is an error to destructively modify any object that appears as a constant in executable code, whether within a 'quote' special form or as a self-evaluating form." This use of the word "constant" is consistent with what's in the emacs-27 doc. > Elisp corresponds > to the behavior of CLTL1 in this regard, not to any > later update Those older CLtL semantics were not well-defined, and to the extent that they were defined were not followed by Common Lisp implementations. It's not clear that the emacs-27 Elisp implementation corresponds to those older semantics, and it's also not clear that documenting CLtL1 semantics would be a good idea for Elisp. > A few mails ago, you wondered if the disagreement > has been only about terminology. And the response > was mostly "Yes" - objections to your use of > "mutable" and "constant"/"immutable", and your use > of "cannot" instead of "should not" (aka "Don't"). > > You've since ignored that response, it seems. I responded to those specific wording objections by removing the "immutable"s and "cannots" that were objected to. At least, that was my intent; if I missed something please let me know. I admit I have not made changes in response to vaguer suggestions, but that's partly because I don't really understand what's involved. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 1:38 ` Paul Eggert @ 2020-04-29 4:36 ` Drew Adams 2020-04-29 16:18 ` Paul Eggert 2020-05-01 3:13 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-29 4:36 UTC (permalink / raw) To: Paul Eggert, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > > You're _not_ using the language that's used > > for Common Lisp. > > In what sense does the language differ? Here's > a quote from CLtL2 (page 115): > > "it is an error to destructively modify any object that appears as a > constant in executable code, whether within a 'quote' special form or as > a self-evaluating form." > > This use of the word "constant" is consistent > with what's in the emacs-27 doc. I quoted that same text as part of a proposal to FIX the very gotcha that Elisp still suffers from. I already addressed this, specifically. See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=40671#24 I specifically spoke of CLTL1, because its state, and the state of CL at that time corresponds more closely with that of Elisp and its doc, since CLTL1 predates the proposal to handle the gotcha systematically. > > Elisp corresponds to the behavior of CLTL1 in > > this regard, not to any later update > > Those older CLtL semantics were not well-defined, Precisely the problem Emacs Lisp has! And not just not well defined. Different behavior sometimes between interpreted and compiled code. That IS the gotcha - the fact that Elisp does NOT raise an error systematically in all such cases. It does NOT always prevent you from modifying a constant, quoted list etc. Elisp is like CL was BEFORE the proposal I quoted, which was adopted as the CLTL2 text you quoted. They fixed the problem for CL by redefining CL to not have it. For an implementation of CL to follow the updated definition, it must provide consistent behavior, preventing modification of constants, quoted lists, etc. Sound familiar yet? > and to the extent that they were defined were not > followed by Common Lisp implementations. It's not > clear that the emacs-27 Elisp implementation > corresponds to those older semantics, and it's > also not clear that documenting CLtL1 semantics > would be a good idea for Elisp. The point is that the problem they fixed is the problem Elisp still has. Whether it is exactly the same in all particulars is unimportant - it's about the behavior being undefined and not necessarily the same if interpreted or compiled. I mentioned the CL proposal, to take effect for CLTL2, quoting: "clarify that it is an error to destructively ^^^^^^^ ^^^^^^^^^^^^^^ modify objects which are self-evaluating forms or which appear inside of a QUOTE special form." Why "clarify"? Because it was NOT stated as part of the previous definition of CL that that is an error. And that meant that CL implementations were NOT required to systematically raise an error to enforce that. They did NOT always prevent you from modifying such thingies. The proposal also said: "Disallowing modification of constants ^^^^^^^^^^^ consistently in all situations, rather than ^^^^^^^^^^^^ just in compiled code, is proposed because ^^^^^^^^^^^ in some compiled-only situations it may be difficult to distinguish between "compiled" and "interpreted" code." That was the problem to be fixed, by raising an error, i.e., by disallowing, in practice. And that's exactly the problem that Elisp still has: it does NOT disallow (systematic error). And no amount of saying that it does (claiming you "cannot" do it) changes that fact. I quoted CLTL about the behavior before the proposal, i.e., before systematically raising an error: "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." And about that I said: Unpredictable behavior. It doesn't say it's ^^^^^^^ always impossible to modify such things. It ^^^^^^^^^^^^^^^^^ says, in effect, don't try. ^^^^^^^^^ That's what we should say for Emacs Lisp, since ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ we do NOT "disallow modification of constants consistently in all situations." For Emacs Lisp this is a gotcha, so we need a SHOULD. If it were enforced as a MUST then we wouldn't need such a caveat. That's precisely the point. We do NOT disallow. We do NOT always raise an error. We do NOT always PREVENT changing quoted list structure etc. AND SO we should NOT tell users that they CANNOT do so - sometimes they CAN. We should instead tell them that they SHOULD NOT try to do so, and if they do then the resulting behavior is undefined. ___ I said last message that I gave up. And now I'm literally repeating what I wrote 10 days ago. You haven't heard, or you're not listening. (And my impression is that others have said the same as I, or similar.) Sorry, I'm done. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 4:36 ` Drew Adams @ 2020-04-29 16:18 ` Paul Eggert 2020-05-01 2:47 ` Richard Stallman 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-29 16:18 UTC (permalink / raw) To: Drew Adams, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 9:36 PM, Drew Adams wrote: > Elisp is like CL was BEFORE the proposal I quoted, No, that's backwards. CLtL1 was hazy, but arguably would have disallowed Elisp's behavior because it arguably required the interpreter to immediately respond to changes in objects currently being executed, and arguably required the interpreter to not coalesce identical literals, and the Elisp interpreter violates both requirements. In contrast, CLtL2 allows the Elisp behavior, so CLtL2 is the better way to go here. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 16:18 ` Paul Eggert @ 2020-05-01 2:47 ` Richard Stallman 2020-05-01 6:23 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Richard Stallman @ 2020-05-01 2:47 UTC (permalink / raw) To: Paul Eggert; +Cc: ke.vigouroux, 40671, michael_heerdegen, mattiase, dgutov [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] To a purist, the vagueness about what happens to Emacs if you modify code at the wrong time may seem intolerable. If there were an easy and painless way to implement well-defined behavior, it might be worth doing so. But there isn't. This isn't a big difficulty in practice. It isn't worth sacrificing anything that matters. -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 2:47 ` Richard Stallman @ 2020-05-01 6:23 ` Eli Zaretskii 0 siblings, 0 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-05-01 6:23 UTC (permalink / raw) To: rms; +Cc: ke.vigouroux, eggert, 40671, michael_heerdegen, mattiase, dgutov > From: Richard Stallman <rms@gnu.org> > Date: Thu, 30 Apr 2020 22:47:32 -0400 > Cc: ke.vigouroux@laposte.net, 40671@debbugs.gnu.org, michael_heerdegen@web.de, > mattiase@acm.org, dgutov@yandex.ru > > To a purist, the vagueness about what happens to Emacs if you modify > code at the wrong time may seem intolerable. If there were an easy > and painless way to implement well-defined behavior, it might be worth > doing so. But there isn't. > > This isn't a big difficulty in practice. It isn't worth sacrificing > anything that matters. I agree, but the practical problem is that we have a couple of purists on board, for whom this is an itch they scratch not too infrequently. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 1:38 ` Paul Eggert 2020-04-29 4:36 ` Drew Adams @ 2020-05-01 3:13 ` Dmitry Gutov 2020-05-01 5:15 ` Drew Adams 2020-05-01 21:40 ` Paul Eggert 1 sibling, 2 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-01 3:13 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 29.04.2020 04:38, Paul Eggert wrote: > On 4/28/20 5:55 PM, Drew Adams wrote: >> You're_not_ using the language that's used for Common Lisp. > In what sense does the language differ? Here's a quote from CLtL2 (page 115): > > "it is an error to destructively modify any object that appears as a constant > in executable code, whether within a 'quote' special form or as > a self-evaluating form." As Drew pointed out (and if I understood this correctly), the above specification leads to implementations that do raise an error when someone tried to modify such a value. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 3:13 ` Dmitry Gutov @ 2020-05-01 5:15 ` Drew Adams 2020-05-01 21:40 ` Paul Eggert 1 sibling, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-05-01 5:15 UTC (permalink / raw) To: Dmitry Gutov, Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > >> You're _not_ using the language that's used for Common Lisp. > > In what sense does the language differ? Here's a quote from CLtL2 > (page 115): > > > > "it is an error to destructively modify any object that appears as a > constant > > in executable code, whether within a 'quote' special form or as > > a self-evaluating form." > > As Drew pointed out (and if I understood this correctly), the above > specification leads to implementations that do raise an error when > someone tried to modify such a value. That's my understanding. I believe that wasn't the case for CLTL(1) - there was no such promise or requirement. And I think it's also not the case for Elisp. Like CLTL(1), we should just warn users about the gotcha, since there's no protection from it. To be clear, I'm no expert on CLTL2. I used CL for years before that. The gotcha bit me once, having modified the result of a quoted list - and then someone explained what was happening. It's too easy for a newbie to think only in terms of textual source code being interpreted. It's easy not to realize, as Michael said, that there's the Lisp reader, the interpreter, and the byte-compiler, and each might get a chance to handle a quoted list. And just how they did so was not specified. Presumably, a conformant CL implementation now protects you from this gotcha. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 3:13 ` Dmitry Gutov 2020-05-01 5:15 ` Drew Adams @ 2020-05-01 21:40 ` Paul Eggert 2020-05-01 22:05 ` Drew Adams 2020-05-02 1:07 ` Dmitry Gutov 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-01 21:40 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/30/20 8:13 PM, Dmitry Gutov wrote: > On 29.04.2020 04:38, Paul Eggert wrote: >> Here's a quote from CLtL2 (page 115): >> >> "it is an error to destructively modify any object that appears as a constant >> in executable code, whether within a 'quote' special form or as >> a self-evaluating form." > > As Drew pointed out (and if I understood this correctly), the above > specification leads to implementations that do raise an error when someone tried > to modify such a value. Although those implementations conform to the Common Lisp spec, that's because the spec explicitly says such behavior is undefined - which means implementations can signal an error, dump core, or do whatever else they want. See <https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node11.html>, which uses "should" in the same sense the emacs-27 elisp manual uses "should". Here's a quote: ----- When this book specifies that it "is an error" for some situation to occur, this means that: * No valid Common Lisp program should cause this situation to occur. * If this situation occurs, the effects and results are completely undefined as far as adherence to the Common Lisp specification is concerned. * No Common Lisp implementation is required to detect such an error. Of course, implementors are encouraged to provide for detection of such errors wherever reasonable. This is not to say that some particular implementation might not define the effects and results for such a situation; the point is that no program conforming to the Common Lisp specification may correctly depend on such effects or results. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 21:40 ` Paul Eggert @ 2020-05-01 22:05 ` Drew Adams 2020-05-01 22:28 ` Paul Eggert 2020-05-02 1:07 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-05-01 22:05 UTC (permalink / raw) To: Paul Eggert, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > >> Here's a quote from CLtL2 (page 115): > >> > >> "it is an error to destructively modify any object that appears as a > >> constant in executable code, whether within a 'quote' special form or as > >> a self-evaluating form." > > > > As Drew pointed out (and if I understood this correctly), the above > > specification leads to implementations that do raise an error when > > someone tried to modify such a value. > > Although those implementations conform to the Common Lisp spec, that's > because the spec explicitly says such behavior is undefined - which means > implementations can signal an error, dump core, or do whatever else > they want. > See > <https://urldefense.com/v3/__https://www.cs.cmu.edu/Groups/AI/html/cltl > /clm/node11.html__;!!GqivPVa7Brio!NeqWMrCFKgi8Ktwdz5aIkeBh_-TPzH- > XiJbWDMeSRu1VKiI70b5LK6Sy2v5CMxaq$ >, which uses > "should" in the same sense the emacs-27 elisp manual uses "should". I stand corrected. I was assuming that the "proposal" I cited had actually been adopted for CLTL2. So CLTL2 is in the same boat as CLTL(1), in the regard relevant to this thread: There is NO systematic raising of an error - no prevention of the gotcha. So what I said about Elisp being like CLTL(1) applies also to CLTL2: We should NOT say that you _cannot_ do XYZ (because you might be able to, and the behavior if you try is undefined). We should instead say that you _should not_. We're still circling, though. But thanks for clarifying that "it's an error" meaning. I misremembered that as meaning that a conformant implementation is required to raise an error. I was thinking/assuming that the cited proposal was in fact adopted as part of the CL definition. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 22:05 ` Drew Adams @ 2020-05-01 22:28 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-01 22:28 UTC (permalink / raw) To: Drew Adams, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/1/20 3:05 PM, Drew Adams wrote: > We should NOT say that you _cannot_ > do XYZ (because you might be able to, and the behavior > if you try is undefined). We should instead say that > you _should not_. That's what the emacs-27 manual does now. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-01 21:40 ` Paul Eggert 2020-05-01 22:05 ` Drew Adams @ 2020-05-02 1:07 ` Dmitry Gutov 2020-05-02 6:28 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-02 1:07 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 02.05.2020 00:40, Paul Eggert wrote: >> As Drew pointed out (and if I understood this correctly), the above >> specification leads to implementations that do raise an error when someone tried >> to modify such a value. > > Although those implementations conform to the Common Lisp spec, that's because > the spec explicitly says such behavior is undefined - which means > implementations can signal an error, dump core, or do whatever else they want. > See <https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node11.html>, which uses > "should" in the same sense the emacs-27 elisp manual uses "should". I suppose so. > When this book specifies that it "is an error" for some situation to occur, this > means that: > > * No valid Common Lisp program should cause this situation to occur. > > * If this situation occurs, the effects and results are completely undefined as > far as adherence to the Common Lisp specification is concerned. > > * No Common Lisp implementation is required to detect such an error. Of course, > implementors are encouraged to provide for detection of such errors wherever > reasonable. > > This is not to say that some particular implementation might not define the > effects and results for such a situation; the point is that no program > conforming to the Common Lisp specification may correctly depend on such effects > or results. Indeed. I took a longer look around the CLtL, to see how the term "constant" is used there, though. Some phrases: --- ...it is an error to destructively modify any object that appears as a constant in executable code, whether as a self-evaluating form or within a quote special form ...to specify what objects can be in compiled constants... quoted constants in it are similar in this sense to quoted constants in the corresponding source code An object may be used as a quoted constant... Some types of objects, such as streams, are not supported in constants processed by the file compiler. Such objects may not portably appear as constants in code processed with compile-file. The following terms are used throughout this section. The term constant refers to a quoted or self-evaluating constant, not a named constant defined by defconstant. Two objects are similar as a constant if and only if they are both of one of the types listed below and satisfy... Two conses are similar as constants if the values of their respective car and cdr attributes are similar as constants. (Then comes the description of "similar as constants" values being coalesced in compiled code). --- CL's terminology seems fairly old by today's standards, but it looks like they were grasping for words, just as we are now. They very rarely use the phrase "constant objects", however. Instead, it's almost always "objects that appears as a constant [in code]", "object ... used as a quoted constant", "object may not ... appear as constants in code", "objects are similar as a constant". IOW, it's the difference between constant values and constant pointers to [mutable] values. And the users are advised not to change the objects that "appear as constants"/[play the role of constants]/[are the values of constants] in executable code. And there is no juxtaposition of "mutable objects" vs "constant objects" anywhere in there, with "constant" defined like that, which is the part of our new documentation that really got me into this discussion. So the section "Constants and Mutability", even though it has valuable information, could use a full rewrite. And could probably move to end of the "Self-Evaluating Forms" section. I'm also not sure it's a good idea to add too much explanations to the introduction featuring phrases like "a list that is part of the program and bad things could happen if we tried to change part of the program while running it", so I'd keep the changes in the examples (the ones I looked at look sensible), but remove most of the explanations. Moreso that they are using the phrases "mutable values" and "constant values". Some short explanation could say that it's a bad idea to modify a quoted form (and then reference "Self-Evaluating Forms"). I can try to make a patch, but at this point is would consist mostly of deletions. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-02 1:07 ` Dmitry Gutov @ 2020-05-02 6:28 ` Paul Eggert 2020-05-02 15:42 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-02 6:28 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/1/20 6:07 PM, Dmitry Gutov wrote: > They very rarely use the phrase "constant objects", however. Instead, it's > almost always "objects that appears as a constant [in code]", "object ... used > as a quoted constant", "object may not ... appear as constants in code", > "objects are similar as a constant". We could use similar circumlocutions. Or instead of saying "constant" we could say "unchanging", as distinct from "unchangeable". (It beats "object-that-should-not-be-changed" or "glass object - you changed it, you broke it!". :-) The usual word for this notion is "constant", though. > IOW, it's the difference between constant values and constant pointers to > [mutable] values. I don't see that. A constant (or "unchanging") string is like a mutable string, except you shouldn't change it. There's no sense in CLtL in which a mutable object must be implemented via a pointer to a value whereas a constant must not be implemented that way. > there is no juxtaposition of "mutable objects" vs "constant objects" > anywhere in there Yes, the mutable/immutable terminology revolution happened mostly after CLtL was written. > So the section > "Constants and Mutability", even though it has valuable information, could use a > full rewrite. And could probably move to end of the "Self-Evaluating Forms" > section. Whether an object is constant is distinct from whether it's derived from a self-evaluating form, because one can have constants that were never derived from any self-evaluating form. Any doc rewrite should be careful to keep the two notions distinct, quite plausibily (though not necessarily) in different sections. > I can try to make a patch, but at this point is would consist mostly of deletions. Certainly some stuff could be deleted (the tutorial could be trimmed as you suggest, for example), but we should keep the baby while we're throwing out the bathwater. And if we're using circumlocutions the text is likely to get longer, not shorter. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-02 6:28 ` Paul Eggert @ 2020-05-02 15:42 ` Dmitry Gutov 2020-05-02 19:35 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-02 15:42 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 02.05.2020 09:28, Paul Eggert wrote: > On 5/1/20 6:07 PM, Dmitry Gutov wrote: > >> They very rarely use the phrase "constant objects", however. Instead, it's >> almost always "objects that appears as a constant [in code]", "object ... used >> as a quoted constant", "object may not ... appear as constants in code", >> "objects are similar as a constant". > > We could use similar circumlocutions. Or instead of saying "constant" we could > say "unchanging", as distinct from "unchangeable". (It beats > "object-that-should-not-be-changed" or "glass object - you changed it, you broke > it!". :-) The usual word for this notion is "constant", though. "glass objects" or "voldemort objects" all sound better to me. :-) "unchanging" is one of the meanings of "constant". It's a property of a process, not something we can call a value out of context. CLtL uses the term "coalesced", though. We can consider it. >> IOW, it's the difference between constant values and constant pointers to >> [mutable] values. > > I don't see that. A constant (or "unchanging") string is like a mutable string, > except you shouldn't change it. An unchanging string is just a string that nobody changed. "Please don't change unchanging strings" is a prohibition of time travel. > There's no sense in CLtL in which a mutable > object must be implemented via a pointer to a value whereas a constant must not > be implemented that way. The "objects that appear as a constant" are objects to which exist references from executable code, and where such references are "constant" (or possibly constant, since an implementation might opt not to coalesce the values). That why it's about constant references (and objects to which such references exist). >> there is no juxtaposition of "mutable objects" vs "constant objects" >> anywhere in there > > Yes, the mutable/immutable terminology revolution happened mostly after CLtL was > written. Not just because of that. >> So the section >> "Constants and Mutability", even though it has valuable information, could use a >> full rewrite. And could probably move to end of the "Self-Evaluating Forms" >> section. > > Whether an object is constant is distinct from whether it's derived from a > self-evaluating form, because one can have constants that were never derived > from any self-evaluating form. Examples? I mean, A mutable object can become constant if it is part of an expression that is evaluated does add some cases not covered by self-evaluating forms, but those are more complex cases (e.g. creating forms programmatically and then passing them to 'eval'), and then the programmer might justifiably be expected to use their head. The self-evaluating forms case is arguably less obvious. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-02 15:42 ` Dmitry Gutov @ 2020-05-02 19:35 ` Paul Eggert 2020-05-03 1:30 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-02 19:35 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman >> There's no sense in CLtL in which a mutable >> object must be implemented via a pointer to a value whereas a constant must not >> be implemented that way. > > The "objects that appear as a constant" are objects to which exist references > from executable code, and where such references are "constant" (or possibly > constant, since an implementation might opt not to coalesce the values). That > why it's about constant references (and objects to which such references exist). I don't understand this point. It sounds like you might be trying to distinguish between constant references (i.e., pointers that don't change) and constant objects implemented via references (i.e., the pointed-to values don't change). However, whether the references themselves are constant is independent of the issue at hand. The issue wouldn't change, for example, if Emacs relocated objects so that references were updated regardless of whether the objects' values were constant. >> Whether an object is constant is distinct from whether it's derived from a >> self-evaluating form, because one can have constants that were never derived >> from any self-evaluating form. > > Examples? One example is (aset (symbol-name 'car) 0 ?d), which I mentioned a while ago. Here's a trickier one: (let ((constant-string (aref (symbol-function 'error) 1))) (aset constant-string 0 183) (number-sequence 0 1 0)) This also provokes undefined behavior at the C level while number-sequence is doing its thing; my Emacs dumps core, yours may do something different. I'm sure there are other examples. The point is that programs should not modify constants. It would be nice if Emacs reliably signaled these errors and we should be able to do a better job of that than we're doing now. However, doing a better job would require interpreter surgery that would be too much for emacs-27. > A mutable object can become constant if it is part of an expression > that is evaluated > > does add some cases not covered by self-evaluating forms, but those are more > complex cases (e.g. creating forms programmatically and then passing them to > 'eval'), and then the programmer might justifiably be expected to use their > head. The self-evaluating forms case is arguably less obvious. The documentation should not limit itself to self-evaluating forms when discussing this problem area. Although it's OK for the doc to emphasize self-evaluating forms, they are not the whole story here. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-02 19:35 ` Paul Eggert @ 2020-05-03 1:30 ` Dmitry Gutov 2020-05-03 7:40 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-03 1:30 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 02.05.2020 22:35, Paul Eggert wrote: >> The "objects that appear as a constant" are objects to which exist references >> from executable code, and where such references are "constant" (or possibly >> constant, since an implementation might opt not to coalesce the values). That >> why it's about constant references (and objects to which such references exist). > > I don't understand this point. > > It sounds like you might be trying to distinguish between constant references > (i.e., pointers that don't change) and constant objects implemented via > references (i.e., the pointed-to values don't change). I'm making a semantic point: these values are special because they are at the other end of a certain set of "constant references". Not because they have any other property themselves, like being immutable. > However, whether the > references themselves are constant is independent of the issue at hand. The > issue wouldn't change, for example, if Emacs relocated objects so that > references were updated regardless of whether the objects' values were constant. Object relocation is immaterial for the semantics of Elisp. Even if the objects were relocated from time to time, the references would be updated, and would point to the same objects again, and thus be constant. >>> Whether an object is constant is distinct from whether it's derived from a >>> self-evaluating form, because one can have constants that were never derived >>> from any self-evaluating form. >> >> Examples? > > One example is (aset (symbol-name 'car) 0 ?d), which I mentioned a while ago. > Here's a trickier one: > > (let ((constant-string (aref (symbol-function 'error) 1))) > (aset constant-string 0 183) > (number-sequence 0 1 0)) > > This also provokes undefined behavior at the C level while number-sequence is > doing its thing; my Emacs dumps core, yours may do something different. I'm sure > there are other examples. The point is that programs should not modify constants. These two are pretty obviously "undefined behavior", and anybody who does that have only themselves to blame. So of course it's good to document this, but since apparently you're not going to fix the semantic problem currently under discussion yourself, I'm not sure I can keep this info. You're welcome to re-add it, of course. > It would be nice if Emacs reliably signaled these errors and we should be able > to do a better job of that than we're doing now. However, doing a better job > would require interpreter surgery that would be too much for emacs-27. Of course. >> A mutable object can become constant if it is part of an expression >> that is evaluated >> >> does add some cases not covered by self-evaluating forms, but those are more >> complex cases (e.g. creating forms programmatically and then passing them to >> 'eval'), and then the programmer might justifiably be expected to use their >> head. The self-evaluating forms case is arguably less obvious. > > The documentation should not limit itself to self-evaluating forms when > discussing this problem area. Although it's OK for the doc to emphasize > self-evaluating forms, they are not the whole story here. The "whole story" can be enumerated in some place, sure. Self-evaluating forms seem to be the most important area to cover, though. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 1:30 ` Dmitry Gutov @ 2020-05-03 7:40 ` Paul Eggert 2020-05-03 16:44 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-03 7:40 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/2/20 6:30 PM, Dmitry Gutov wrote: > I'm making a semantic point: these values are special because they are at the > other end of a certain set of "constant references". Not because they have any > other property themselves, like being immutable. I don't see why this semantic point makes a difference to the user. Regardless of whether the objects are targets of "constant references" (whatever that means), programs should not modify the objects in question. And if the semantic point makes no practical difference, why complicate the manual with it? It's simpler just to say: programs shouldn't modify these objects. > The "whole story" can be enumerated in some place, sure. Self-evaluating forms > seem to be the most important area to cover, though. They're not the only thing to cover, and attempting to shoehorn this all into self-evaluating forms could even be misleading. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 7:40 ` Paul Eggert @ 2020-05-03 16:44 ` Dmitry Gutov 2020-05-03 20:48 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-03 16:44 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 03.05.2020 10:40, Paul Eggert wrote: > It's simpler just to say: programs shouldn't modify these objects. Which objects, then? > They're not the only thing to cover, and attempting to shoehorn this all into > self-evaluating forms could even be misleading. Which section would that go into? "Constants and Mutability" doesn't work. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 16:44 ` Dmitry Gutov @ 2020-05-03 20:48 ` Paul Eggert 2020-05-03 22:17 ` Dmitry Gutov 2020-05-03 22:18 ` Dmitry Gutov 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-03 20:48 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/3/20 9:44 AM, Dmitry Gutov wrote: > On 03.05.2020 10:40, Paul Eggert wrote: >> It's simpler just to say: programs shouldn't modify these objects. > > Which objects, then? Objects that the documentation currently calls "constants". (If there's a better term than "constants" we haven't found it yet.) >> They're not the only thing to cover, and attempting to shoehorn this all into >> self-evaluating forms could even be misleading. > > Which section would that go into? "Constants and Mutability" doesn't work. If we change the word "constants" to something else, we would presumably retitle the section and adjust its contents accordingly. Regardless of which word is chosen we should document the issue, which is broader than that of constants from self-evaluating forms. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 20:48 ` Paul Eggert @ 2020-05-03 22:17 ` Dmitry Gutov 2020-05-03 22:18 ` Dmitry Gutov 1 sibling, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-03 22:17 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 03.05.2020 23:48, Paul Eggert wrote: > If we change the word "constants" to something else, we would presumably retitle > the section and adjust its contents accordingly. Regardless of which word is > chosen we should document the issue, which is broader than that of constants > from self-evaluating forms. Yes. But you supposedly want to move some of the contents (which don't pertain exactly to self-evaluating forms) to some other section. Could you make that naming choice yourself? I can only move it to one of the existing ones. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 20:48 ` Paul Eggert 2020-05-03 22:17 ` Dmitry Gutov @ 2020-05-03 22:18 ` Dmitry Gutov 2020-05-03 22:39 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-03 22:18 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 03.05.2020 23:48, Paul Eggert wrote: > (If there's a better > term than "constants" we haven't found it yet.) "Objects referenced from executable code", presumably. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 22:18 ` Dmitry Gutov @ 2020-05-03 22:39 ` Paul Eggert 2020-05-03 22:53 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-03 22:39 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/3/20 3:18 PM, Dmitry Gutov wrote: > On 03.05.2020 23:48, Paul Eggert wrote: >> (If there's a better >> term than "constants" we haven't found it yet.) > > "Objects referenced from executable code", presumably. A fair number of objects fit that category. (The objects that don't are typically garbage collected. :-) So that term doesn't describe what we want clearly and accurately; plus, it's pretty long.... > On 03.05.2020 23:48, Paul Eggert wrote: >> If we change the word "constants" to something else, we would presumably retitle >> the section and adjust its contents accordingly. Regardless of which word is >> chosen we should document the issue, which is broader than that of constants >> from self-evaluating forms. > > Yes. But you supposedly want to move some of the contents (which don't pertain exactly to self-evaluating forms) to some other section. There must be some miscommunication, as I thought you wanted to move some of that section's contents. I vaguely recall responding that something along those lines could work, but I don't recall any specific suggestion after that. > Could you make that naming choice yourself? I can only move it to one of the existing ones. I don't understand this request; I don't know what you mean by "it" or by "moving" or by "existing ones". If you're talking about the title of the "Constants and Mutability" section, the current term "constants" is fine with me, as it follows existing practice in CLtL etc. I'm open for suggestions for changing the term, but we haven't come up with a better term as far as I can see, or even a term that's roughly equal in quality. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 22:39 ` Paul Eggert @ 2020-05-03 22:53 ` Dmitry Gutov 2020-05-03 23:10 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-03 22:53 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 04.05.2020 01:39, Paul Eggert wrote: > A fair number of objects fit that category. (The objects that don't > are typically garbage collected. So that term doesn't describe what > we want clearly and accurately; plus, it's pretty long.... Example, please. > If you're talking about the title of the "Constants and Mutability" section, the > current term "constants" is fine with me, as it follows existing practice in > CLtL etc. I'm open for suggestions for changing the term, but we haven't come up > with a better term as far as I can see, or even a term that's roughly equal in > quality. I'm clearly not the only one objecting to the new terms. And especially the juxtaposition of "constants and mutability" that you added to the docs. It would be a shame to revert your whole work, though. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 22:53 ` Dmitry Gutov @ 2020-05-03 23:10 ` Paul Eggert 2020-05-04 10:16 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-03 23:10 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/3/20 3:53 PM, Dmitry Gutov wrote: > On 04.05.2020 01:39, Paul Eggert wrote: >> A fair number of objects fit that category. (The objects that don't >> are typically garbage collected. So that term doesn't describe what >> we want clearly and accurately; plus, it's pretty long.... > > Example, please. The term you used was "Objects referenced from executable code". But that term includes pretty much every object used in Elisp, at least until the object becomes unreachable and is garbage-collected. The concept you were describing is not that general: it's limited to objects that are part of an expressions that are evaluated. So a better term would be something like "Objects that are part of expressions that are evaluated" - but this term is way too long; plus it doesn't accurately describe all the problematic objects, as there are other reasons that some objects should not be modified. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-03 23:10 ` Paul Eggert @ 2020-05-04 10:16 ` Dmitry Gutov 2020-05-04 17:52 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-04 10:16 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 04.05.2020 02:10, Paul Eggert wrote: > The term you used was "Objects referenced from executable code". But that term > includes pretty much every object used in Elisp, at least until the object > becomes unreachable and is garbage-collected. I see. Could you present a specific counter-example, however? One where the phrasing "referenced from executable code" would apply, but "part of expressions that are evaluated" wouldn't. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-04 10:16 ` Dmitry Gutov @ 2020-05-04 17:52 ` Paul Eggert 2020-05-05 1:39 ` Dmitry Gutov 2020-05-05 20:48 ` Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-04 17:52 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/4/20 3:16 AM, Dmitry Gutov wrote: > On 04.05.2020 02:10, Paul Eggert wrote: >> The term you used was "Objects referenced from executable code". But that term >> includes pretty much every object used in Elisp, at least until the object >> becomes unreachable and is garbage-collected. > > I see. Could you present a specific counter-example, however? > > One where the phrasing "referenced from executable code" would apply, but "part > of expressions that are evaluated" wouldn't. Pretty much any ordinary cons will do. In (let ((x (cons 0 0))) (setcar x 1)), for example, the cons is referenced from executable code but it's OK to modify the cons. The cons becomes unreachable when the 'let' finishes. The cons is not part of any expression that is evaluated. The problem here evidently is one of terminology, not of understanding the underlying issues. When I read "Objects referenced from executable code" I evidently got a different meaning than what you intended. These things happen when introducing a new terminology. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-04 17:52 ` Paul Eggert @ 2020-05-05 1:39 ` Dmitry Gutov 2020-05-05 6:09 ` Paul Eggert 2020-05-05 20:48 ` Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-05 1:39 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman [-- Attachment #1: Type: text/plain, Size: 1215 bytes --] On 04.05.2020 20:52, Paul Eggert wrote: > Pretty much any ordinary cons will do. In (let ((x (cons 0 0))) (setcar x 1)), > for example, the cons is referenced from executable code but it's OK to modify > the cons. The cons becomes unreachable when the 'let' finishes. The cons is not > part of any expression that is evaluated. But, I mean, if we just make it a literal: (let ((x '(0 . 0))) (setcar x 1)) ...it also becomes okay to modify it because the cons becomes unreachable right away. Even so, we strongly recommend against this in the manual now. When the form above is a part of a function body, however, then it's *really* inadvisable to use the latter option. > The problem here evidently is one of terminology, not of understanding the > underlying issues. When I read "Objects referenced from executable code" I > evidently got a different meaning than what you intended. These things happen > when introducing a new terminology. I have asked for clarification to try to come up with better phrasing. But to be frank it's not so important to me as fixing the existing one. So if you can find a better option, please be my guest. In the meantime, what do you think about the attached patch? [-- Attachment #2: no_constants.diff --] [-- Type: text/x-patch, Size: 16044 bytes --] diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index ea16d9ef15..46462162ca 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7317,8 +7317,6 @@ setcar works is to experiment. We will start with the @code{setcar} function. @need 1200 -@cindex constant lists -@cindex mutable lists First, we can make a list and then set the value of a variable to the list, using the @code{setq} special form. Because we intend to use @code{setcar} to change the list, this @code{setq} should not use the @@ -7327,8 +7325,7 @@ setcar tried to change part of the program while running it. Generally speaking an Emacs Lisp program's components should be constant (or unchanged) while the program is running. So we instead construct an -animal list that is @dfn{mutable} (or changeable) by using the -@code{list} function, as follows: +animal list by using the @code{list} function, as follows: @smallexample (setq animals (list 'antelope 'giraffe 'lion 'tiger)) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index bba1b63115..8abdd6663f 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -297,7 +297,7 @@ Top * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Dangerous Mutations:: Objects which should not be modified. Programming Types diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index baddce4d9c..786c2f2de4 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -158,11 +158,12 @@ Self-Evaluating Forms @end group @end example - A self-evaluating form yields constant conses, vectors and strings, and you -should not attempt to modify their contents via @code{setcar}, @code{aset} or -similar operations. The Lisp interpreter might unify the constants -yielded by your program's self-evaluating forms, so that these -constants might share structure. @xref{Constants and Mutability}. + A self-evaluating form yields a value that becomes part of the +program, and you should not attempt to modify their contents via +@code{setcar}, @code{aset} or similar operations. The Lisp +interpreter might unify the constants yielded by your program's +self-evaluating forms, so that these constants might share structure. +@xref{Dangerous Mutations}. It is common to write numbers, characters, strings, and even vectors in Lisp code, taking advantage of the fact that they self-evaluate. @@ -564,8 +565,6 @@ Quoting @defspec quote object This special form returns @var{object}, without evaluating it. -The returned value is a constant, and should not be modified. -@xref{Constants and Mutability}. @end defspec @cindex @samp{'} for quoting @@ -608,9 +607,9 @@ Quoting Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)} both yield lists equal to @code{(+ 1 2)}, the former yields a -freshly-minted mutable list whereas the latter yields a constant list -built from conses that may be shared with other constants. -@xref{Constants and Mutability}. +freshly-minted new list whereas the latter yields a list +built from conses that may be shared with other values. +@xref{Self-Evaluating Forms}. Other quoting constructs include @code{function} (@pxref{Anonymous Functions}), which causes an anonymous lambda expression written in Lisp @@ -710,7 +709,7 @@ Backquote @end example If a subexpression of a backquote construct has no substitutions or -splices, it acts like @code{quote} in that it yields constant conses, +splices, it acts like @code{quote} in that it yields conses, vectors and strings that should not be modified. @node Eval diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index fcaf4386b1..065853042a 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -866,15 +866,14 @@ List Variables @node Modifying Lists @section Modifying Existing List Structure @cindex destructive list operations -@cindex mutable lists You can modify the @sc{car} and @sc{cdr} contents of a cons cell with the primitives @code{setcar} and @code{setcdr}. These are destructive operations because they change existing list structure. -Destructive operations should be applied only to mutable lists, -that is, lists constructed via @code{cons}, @code{list} or similar -operations. Lists created by quoting are constants and should not be -changed by destructive operations. @xref{Constants and Mutability}. +Destructive operations should be applied only to lists constructed via +@code{cons}, @code{list} or similar operations. Lists created by +quoting are part of the program and should not be changed by destructive +operations. @xref{Dangerous Mutations}. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -911,7 +910,7 @@ Setcar @example @group -(setq x (list 1 2)) ; @r{Create a mutable list.} +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -931,7 +930,7 @@ Setcar @example @group -;; @r{Create two mutable lists that are partly shared.} +;; @r{Create two lists that are partly shared.} (setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @@ -1022,11 +1021,11 @@ Setcdr @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} +(setcdr x '(4)) @result{} (4) @end group @group @@ -1135,11 +1134,11 @@ Rearrangement @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} +(nconc x '(4 5)) @result{} (1 2 3 4 5) @end group @group @@ -1168,7 +1167,7 @@ Rearrangement @end group @end example -However, the other arguments (all but the last) should be mutable lists. +However, the other arguments (all but the last) must be lists. A common pitfall is to use a constant list as a non-last argument to @code{nconc}. If you do this, the resulting behavior diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1d5b2c690f..9fdcb4b1bc 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -46,10 +46,6 @@ Lisp Data Types Lisp variables can only take on values of a certain type. @xref{Variables with Restricted Values}.) - Some Lisp objects are @dfn{constant}: their values should never change. -Others are @dfn{mutable}: their values can be changed via destructive -operations that involve side effects. - This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how to use these types can be found in later chapters. @@ -63,7 +59,7 @@ Lisp Data Types * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Dangerous Mutations:: Objects which should not be modified. @end menu @node Printed Representation @@ -2379,51 +2375,34 @@ Equality Predicates @end example @end defun -@node Constants and Mutability -@section Constants and Mutability -@cindex constants -@cindex mutable objects - - Some Lisp objects are constant: their values should never change -during a single execution of Emacs running well-behaved Lisp code. -For example, you can create a new integer by calculating one, but you -cannot modify the value of an existing integer. - - Other Lisp objects are mutable: it is safe to change their values -via destructive operations involving side effects. For example, an -existing marker can be changed by moving the marker to point to -somewhere else. +@node Dangerous Mutations +@section Dangerous Mutations - Although all numbers are constants and all markers are -mutable, some types contain both constant and mutable members. These -types include conses, vectors, strings, and symbols. For example, the string -literal @code{"aaa"} yields a constant string, whereas the function -call @code{(make-string 3 ?a)} yields a mutable string that can be -changed via later calls to @code{aset}. + Most Lisp programs first create some values, then mutate them. For +this to work well, a new value should generally be created every time +a function is called. When a value is created using a function such +as @code{list}, @code{cons}, @code{make-string} or +@code{copy-sequence}, that happens reliably, and such a value is safe +to modify. - A mutable object can become constant if it is part of an expression -that is evaluated. The reverse does not occur: constant objects -should stay constant. + Modifying the values obtained by evaluating a self-evaluating form +(such as @code{"abc"}) is not advised. Values that appear as part of +a program should not be modified. 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 -resulting behavior is undefined: the Lisp interpreter might or might -not detect the error, and if it does not detect the error the -interpreter can behave unpredictably thereafter. Another way to put -this is that although mutable objects are safe to change and constant -variables reliably prevent attempts to change them, other constants -are not safely mutable: if a misbehaving program tries to change such a -constant then the constant's value might actually change, or the -program might crash or worse. This problem occurs -with types that have both constant and mutable members, and that have -mutators like @code{setcar} and @code{aset} that are valid on mutable -objects but hazardous on constants. - - When the same constant occurs multiple times in a program, the Lisp -interpreter might save time or space by reusing existing constants or -constant components. For example, @code{(eq "abc" "abc")} returns +(@pxref{Constant Variables}). The current version of Emacs might not +signal an error when a dangerous mutation occurs, however. The result +is essentially undefined: the Lisp interpreter might or might not +detect the error, and if it does not detect the error the interpreter +can behave unpredictably thereafter. If a misbehaving program tries +to change such a value then it might actually succeed, or the program +might crash or worse. This will hopefully be improved in future +versions of Emacs. + + When the same literal occurs multiple times in a program, the Lisp +interpreter might save time or space by reusing existing values or +their components. For example, @code{(eq "abc" "abc")} returns @code{t} if the interpreter creates only one instance of the string -constant @code{"abc"}, and returns @code{nil} if it creates two -instances. Lisp programs should be written so that they work -regardless of whether this optimization is in use. +@code{"abc"}, and returns @code{nil} if it creates two instances. +Lisp programs should be written so that they work regardless of +whether this optimization is in use. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1cb0d05cc7..e41ce2ebe2 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ Sequence Functions @example @group -(setq bar (list 1 2)) ; @r{Create a mutable list.} +(setq bar (list 1 2)) @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} +(setq x (vector 'foo bar)) @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ Sequence Functions For the vector, it is even simpler because you don't need setq: @example -(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} +(setq x (copy-sequence [1 2 3 4])) @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -330,7 +330,7 @@ Sequence Functions Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly -encouraged to treat strings as immutable even when they are mutable. +encouraged to treat strings as immutable. @end defun @@ -374,7 +374,7 @@ Sequence Functions @example @group -(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1228,7 @@ Array Functions @example @group -(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1237,7 @@ Array Functions @end group @group -;; @r{@code{copy-sequence} creates a mutable string.} +;; @r{@code{copy-sequence} copies the string to be modified later.} (setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @@ -1247,10 +1247,6 @@ Array Functions @end group @end example -The @var{array} should be mutable; that is, it should not be a constant, -such as the constants created via quoting or via self-evaluating forms. -@xref{Constants and Mutability}. - If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a unibyte string to multibyte if necessary to insert a character. @@ -1262,7 +1258,6 @@ Array Functions @example @group -;; @r{Create a mutable vector and then fill it with zeros.} (setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @@ -1271,7 +1266,6 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -;; @r{Create a mutable string and then fill it with "-".} (setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @@ -1309,9 +1303,7 @@ Vectors A vector, like a string or a number, is considered a constant for evaluation: the result of evaluating it is the same vector. This does not evaluate or even examine the elements of the vector. -@xref{Self-Evaluating Forms}. Vectors written with square brackets -are constants and should not be modified via @code{aset} or other -destructive operations. @xref{Constants and Mutability}. +@xref{Self-Evaluating Forms}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index a4c9c2549c..3a6de56584 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -51,8 +51,7 @@ String Basics operate on them with the general array and sequence functions documented in @ref{Sequences Arrays Vectors}. For example, you can access or change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, you should not -try to change the contents of constant strings (@pxref{Modifying Strings}). +and @code{aset} (@pxref{Array Functions}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -383,8 +382,8 @@ Modifying Strings You can alter the contents of a mutable string via operations described in this section. However, you should not try to use these -operations to alter the contents of a constant string. -@xref{Constants and Mutability}. +operations to alter the contents of a string literal. +@xref{Dangerous Mutations}. The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 1:39 ` Dmitry Gutov @ 2020-05-05 6:09 ` Paul Eggert 2020-05-05 12:38 ` Dmitry Gutov 2020-05-05 17:40 ` Drew Adams 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-05 6:09 UTC (permalink / raw) To: Dmitry Gutov, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 5/4/20 6:39 PM, Dmitry Gutov wrote: > if we just make it a literal: > > (let ((x '(0 . 0))) (setcar x 1)) > > ...it also becomes okay to modify it No, because the literal might be placed in read-only storage of some sort. > In the meantime, what do you think about the attached patch? Most of it is OK, but it goes too far in removing useful practical advice about not doing "dangerous mutations" (to use the terminology you prefer). The defspec for quote, the defuns for aset, setcar and setcdr, and the square-bracket notation for vectors, should all point to the Dangerous Mutations section. Also, the section on Dangerous Mutations should not imply that self-evaluating forms are the only way to get objects that are dangerous to mutate, as there are other ways to get such objects. The section Dangerous Mutations is really about Mutations, not merely about Dangerous Mutations. For example, it talks about modifying constant variables. So I suggest changing its name to just "Mutations". This will help us in future versions of Emacs, in which at least some of these mutations should become non-dangerous. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 6:09 ` Paul Eggert @ 2020-05-05 12:38 ` Dmitry Gutov 2020-05-09 6:10 ` Paul Eggert 2020-05-05 17:40 ` Drew Adams 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-05 12:38 UTC (permalink / raw) To: Paul Eggert, Drew Adams Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 05.05.2020 09:09, Paul Eggert wrote: >> In the meantime, what do you think about the attached patch? > > Most of it is OK, but it goes too far in removing useful practical advice about > not doing "dangerous mutations" (to use the terminology you prefer). The defspec > for quote, the defuns for aset, setcar and setcdr, and the square-bracket > notation for vectors, should all point to the Dangerous Mutations section. I think that was too much: we've been living with this problem for many years without hitting it too often. Sticking warning all over seems like an overreaction. > Also, the section on Dangerous Mutations should not imply that self-evaluating > forms are the only way to get objects that are dangerous to mutate, as there are > other ways to get such objects. I thought your explanation was a bit too vague, so I added concreteness. In essence though it was saying constants this and constants that, but the actual examples were also only about self-evaluating forms. Did I delete some informative part? > The section Dangerous Mutations is really about Mutations, not merely about > Dangerous Mutations. For example, it talks about modifying constant variables. > So I suggest changing its name to just "Mutations". This will help us in future > versions of Emacs, in which at least some of these mutations should become > non-dangerous. It's talking about the cases where a modification shouldn't occur, hence the name. When something from the list becomes legal, I think this section will just stop mentioning it? In any case, none of my objections here are strong ones. How about you take the proposed patch and update it as you see fit? As long as "constant values" don't make a comeback, I'm good. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 12:38 ` Dmitry Gutov @ 2020-05-09 6:10 ` Paul Eggert 2020-05-10 3:13 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-09 6:10 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Richard Stallman [-- Attachment #1: Type: text/plain, Size: 627 bytes --] On 5/5/20 5:38 AM, Dmitry Gutov wrote: > In any case, none of my objections here are strong ones. How about you take the > proposed patch and update it as you see fit? As long as "constant values" don't > make a comeback, I'm good. OK, attached is a draft patch to emacs-27. Although it doesn't go as far as your patch, it does keep some of it, and in particular it gets rid of the introduction of the term "constant" to describe objects that should not be changed. It also omits the "Dangerous" that Drew objected to, and gives an example of a term that was formerly mutable but is now something that you should not change. [-- Attachment #2: 0001-Don-t-use-constant-for-values-you-shouldn-t-change.txt --] [-- Type: text/plain, Size: 17465 bytes --] From 702f28be9beea4a0475094140afb85cd4aa366ba Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Fri, 8 May 2020 22:53:41 -0700 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20use=20=E2=80=9Cconstant?= =?UTF-8?q?=E2=80=9D=20for=20values=20you=20shouldn=E2=80=99t=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired by patch proposed by Dmitry Gutov (Bug#40671#393). * doc/lispintro/emacs-lisp-intro.texi (setcar): Don’t push mutability here. * doc/lispref/eval.texi (Self-Evaluating Forms, Quoting) (Backquote): * doc/lispref/lists.texi (Modifying Lists): * doc/lispref/objects.texi (Lisp Data Types, Mutability): * doc/lispref/sequences.texi (Array Functions, Vectors): * doc/lispref/strings.texi (String Basics, Modifying Strings): Don’t use the word “constant” to describe all values that a program should not change. * doc/lispref/objects.texi (Mutability): Rename from “Constants and Mutability”. All uses changed. In a footnote, contrast the Emacs behavior with that of Common Lisp, Python, etc. for clarity, and say the goal is to be nicer. --- doc/lispintro/emacs-lisp-intro.texi | 5 +- doc/lispref/elisp.texi | 2 +- doc/lispref/eval.texi | 21 +++++---- doc/lispref/lists.texi | 16 +++---- doc/lispref/objects.texi | 71 +++++++++++++---------------- doc/lispref/sequences.texi | 25 +++++----- doc/lispref/strings.texi | 11 ++--- 7 files changed, 68 insertions(+), 83 deletions(-) diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index ea16d9ef15..46462162ca 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7317,8 +7317,6 @@ setcar works is to experiment. We will start with the @code{setcar} function. @need 1200 -@cindex constant lists -@cindex mutable lists First, we can make a list and then set the value of a variable to the list, using the @code{setq} special form. Because we intend to use @code{setcar} to change the list, this @code{setq} should not use the @@ -7327,8 +7325,7 @@ setcar tried to change part of the program while running it. Generally speaking an Emacs Lisp program's components should be constant (or unchanged) while the program is running. So we instead construct an -animal list that is @dfn{mutable} (or changeable) by using the -@code{list} function, as follows: +animal list by using the @code{list} function, as follows: @smallexample (setq animals (list 'antelope 'giraffe 'lion 'tiger)) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index bba1b63115..9a6796790c 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -297,7 +297,7 @@ Top * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. Programming Types diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index baddce4d9c..39f342a798 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -158,11 +158,11 @@ Self-Evaluating Forms @end group @end example - A self-evaluating form yields constant conses, vectors and strings, and you -should not attempt to modify their contents via @code{setcar}, @code{aset} or + A self-evaluating form yields a value that becomes part of the program, +and you should not try to modify it via @code{setcar}, @code{aset} or similar operations. The Lisp interpreter might unify the constants yielded by your program's self-evaluating forms, so that these -constants might share structure. @xref{Constants and Mutability}. +constants might share structure. @xref{Mutability}. It is common to write numbers, characters, strings, and even vectors in Lisp code, taking advantage of the fact that they self-evaluate. @@ -564,8 +564,8 @@ Quoting @defspec quote object This special form returns @var{object}, without evaluating it. -The returned value is a constant, and should not be modified. -@xref{Constants and Mutability}. +The returned value might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @end defspec @cindex @samp{'} for quoting @@ -608,9 +608,9 @@ Quoting Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)} both yield lists equal to @code{(+ 1 2)}, the former yields a -freshly-minted mutable list whereas the latter yields a constant list -built from conses that may be shared with other constants. -@xref{Constants and Mutability}. +freshly-minted mutable list whereas the latter yields a list +built from conses that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. Other quoting constructs include @code{function} (@pxref{Anonymous Functions}), which causes an anonymous lambda expression written in Lisp @@ -710,8 +710,9 @@ Backquote @end example If a subexpression of a backquote construct has no substitutions or -splices, it acts like @code{quote} in that it yields constant conses, -vectors and strings that should not be modified. +splices, it acts like @code{quote} in that it yields conses, +vectors and strings that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @node Eval @section Eval diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index fcaf4386b1..ae793d5e15 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -873,8 +873,8 @@ Modifying Lists operations because they change existing list structure. Destructive operations should be applied only to mutable lists, that is, lists constructed via @code{cons}, @code{list} or similar -operations. Lists created by quoting are constants and should not be -changed by destructive operations. @xref{Constants and Mutability}. +operations. Lists created by quoting are part of the program and +should not be changed by destructive operations. @xref{Mutability}. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -911,7 +911,7 @@ Setcar @example @group -(setq x (list 1 2)) ; @r{Create a mutable list.} +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -931,7 +931,7 @@ Setcar @example @group -;; @r{Create two mutable lists that are partly shared.} +;; @r{Create two lists that are partly shared.} (setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @@ -1022,11 +1022,11 @@ Setcdr @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} +(setcdr x '(4)) @result{} (4) @end group @group @@ -1135,11 +1135,11 @@ Rearrangement @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} +(nconc x '(4 5)) @result{} (1 2 3 4 5) @end group @group diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1d5b2c690f..a0afadc2d7 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -46,10 +46,6 @@ Lisp Data Types Lisp variables can only take on values of a certain type. @xref{Variables with Restricted Values}.) - Some Lisp objects are @dfn{constant}: their values should never change. -Others are @dfn{mutable}: their values can be changed via destructive -operations that involve side effects. - This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how to use these types can be found in later chapters. @@ -63,7 +59,7 @@ Lisp Data Types * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. @end menu @node Printed Representation @@ -2379,51 +2375,48 @@ Equality Predicates @end example @end defun -@node Constants and Mutability -@section Constants and Mutability -@cindex constants +@node Mutability +@section Mutability @cindex mutable objects - Some Lisp objects are constant: their values should never change -during a single execution of Emacs running well-behaved Lisp code. -For example, you can create a new integer by calculating one, but you -cannot modify the value of an existing integer. + Some Lisp objects should never change. For example, you can create +a new number by calculating one, but you cannot modify the value of an +existing number. - Other Lisp objects are mutable: it is safe to change their values -via destructive operations involving side effects. For example, an -existing marker can be changed by moving the marker to point to -somewhere else. + Other Lisp objects are @dfn{mutable}: it is safe to change their +values via destructive operations involving side effects. For +example, an existing marker can be changed by moving the marker to +point to somewhere else. - Although all numbers are constants and all markers are -mutable, some types contain both constant and mutable members. These + Although numbers never change and all markers are mutable, a type +can be a hybrid with some members mutable and other members not. These types include conses, vectors, strings, and symbols. For example, the string -literal @code{"aaa"} yields a constant string, whereas the function +literal @code{"aaa"} yields a string that should not be changed, whereas the 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 part of an expression -that is evaluated. The reverse does not occur: constant objects -should stay constant. + A mutable object stops being mutable if it is part of an expression +that is evaluated. For example, in @code{(eval (list 'quote (list 1)))} +the list @code{(1)} was mutable when it was created, but it should not +be changed after it was part of an argument to @code{eval}. The +reverse does not occur: an object that should not be changed never +becomes mutable afterwards. 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 -resulting behavior is undefined: the Lisp interpreter might or might -not detect the error, and if it does not detect the error the -interpreter can behave unpredictably thereafter. Another way to put -this is that although mutable objects are safe to change and constant -variables reliably prevent attempts to change them, other constants -are not safely mutable: if a misbehaving program tries to change such a -constant then the constant's value might actually change, or the -program might crash or worse. This problem occurs -with types that have both constant and mutable members, and that have -mutators like @code{setcar} and @code{aset} that are valid on mutable -objects but hazardous on constants. - - When the same constant occurs multiple times in a program, the Lisp -interpreter might save time or space by reusing existing constants or -constant components. For example, @code{(eq "abc" "abc")} returns +If a program attempts to change other objects that should not be +changed, the resulting behavior is undefined: the Lisp interpreter +might signal an error, or it might crash or behave unpredictably in +other ways.@footnote{This is the behavior specified for languages like +Common Lisp and C, and it differs from the behavior of languages like +JavaScript and Python where an interpreter is required to signal an +error if a program attempts to change a constant. Ideally the Emacs +Lisp interpreter will evolve in latter direction.} + + When the same value appears multiple times in a program, the Lisp +interpreter might save time or space by reusing existing values or +their components. For example, @code{(eq "abc" "abc")} returns @code{t} if the interpreter creates only one instance of the string -constant @code{"abc"}, and returns @code{nil} if it creates two +literal @code{"abc"}, and returns @code{nil} if it creates two instances. Lisp programs should be written so that they work regardless of whether this optimization is in use. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1cb0d05cc7..91c3049f87 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ Sequence Functions @example @group -(setq bar (list 1 2)) ; @r{Create a mutable list.} +(setq bar (list 1 2)) @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} +(setq x (vector 'foo bar)) @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ Sequence Functions For the vector, it is even simpler because you don't need setq: @example -(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} +(setq x (copy-sequence [1 2 3 4])) @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -331,6 +331,7 @@ Sequence Functions Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly encouraged to treat strings as immutable even when they are mutable. +@xref{Mutability}. @end defun @@ -374,7 +375,7 @@ Sequence Functions @example @group -(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1229,7 @@ Array Functions @example @group -(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1238,7 @@ Array Functions @end group @group -;; @r{@code{copy-sequence} creates a mutable string.} +;; @r{@code{copy-sequence} copies the string to be modified later.} (setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @@ -1247,9 +1248,7 @@ Array Functions @end group @end example -The @var{array} should be mutable; that is, it should not be a constant, -such as the constants created via quoting or via self-evaluating forms. -@xref{Constants and Mutability}. +The @var{array} should be mutable. @xref{Mutability}. If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a @@ -1262,7 +1261,6 @@ Array Functions @example @group -;; @r{Create a mutable vector and then fill it with zeros.} (setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @@ -1271,7 +1269,6 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -;; @r{Create a mutable string and then fill it with "-".} (setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @@ -1310,8 +1307,8 @@ Vectors evaluation: the result of evaluating it is the same vector. This does not evaluate or even examine the elements of the vector. @xref{Self-Evaluating Forms}. Vectors written with square brackets -are constants and should not be modified via @code{aset} or other -destructive operations. @xref{Constants and Mutability}. +should not be modified via @code{aset} or other destructive +operations. @xref{Mutability}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index a4c9c2549c..70c3b3cf4b 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -49,10 +49,9 @@ String Basics Since strings are arrays, and therefore sequences as well, you can operate on them with the general array and sequence functions documented -in @ref{Sequences Arrays Vectors}. For example, you can access or -change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, you should not -try to change the contents of constant strings (@pxref{Modifying Strings}). +in @ref{Sequences Arrays Vectors}. For example, you can access +individual characters in a string using the function @code{aref} +(@pxref{Array Functions}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -382,9 +381,7 @@ Modifying Strings @cindex string modification You can alter the contents of a mutable string via operations -described in this section. However, you should not try to use these -operations to alter the contents of a constant string. -@xref{Constants and Mutability}. +described in this section. @xref{Mutability}. The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-09 6:10 ` Paul Eggert @ 2020-05-10 3:13 ` Dmitry Gutov 2020-05-10 13:34 ` Dmitry Gutov 2020-05-10 17:29 ` Paul Eggert 0 siblings, 2 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-10 3:13 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Richard Stallman Hi Paul, On 09.05.2020 09:10, Paul Eggert wrote: > On 5/5/20 5:38 AM, Dmitry Gutov wrote: > >> In any case, none of my objections here are strong ones. How about you take the >> proposed patch and update it as you see fit? As long as "constant values" don't >> make a comeback, I'm good. > OK, attached is a draft patch to emacs-27. Although it doesn't go as far as your > patch, it does keep some of it, and in particular it gets rid of the > introduction of the term "constant" to describe objects that should not be > changed. It also omits the "Dangerous" that Drew objected to, and gives an > example of a term that was formerly mutable but is now something that you should > not change. It's an improvement, but still I don't understand your choice. Starting with: Some Lisp objects should never change. For example, you can create a new number by calculating one, but you cannot modify the value of an existing number. You start talking about objects that "should [not] change". And give an example of an object that _cannot_ change. Then, this passage is still confusing, and it doesn't have to be: Although numbers never change and all markers are mutable, a type can be a hybrid with some members mutable and other members not. I could understand it if it was describing an existing type system of the language, or implementation internals, but this is a purely imaginary type system. Why make the mental image harder than we have to? Further down: A mutable object stops being mutable if it is part of an expression that is evaluated. For example, in @code{(eval (list 'quote (list 1)))} the list @code{(1)} was mutable when it was created, but it should not be changed after it was part of an argument to @code{eval}. But the list object didn't change, just an outside reference to its head was created, and that made it "possibly shared", depending on how the aggregated value is subsequently used. And further: ...whereas the call @code{(make-string 3 ?a)} yields a mutable string that can be changed via later calls to @code{aset} The opposite of "mutable" is "immutable". Are quoted strings immutable? They are not. Overall the phrase "that might be shared" is a good replacement. Why not keep to it? The rest of the patch doesn't try so hard to force the new definitions anymore, so your new meaning of "mutable" doesn't seem indispensable. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-10 3:13 ` Dmitry Gutov @ 2020-05-10 13:34 ` Dmitry Gutov 2020-05-10 17:29 ` Paul Eggert 1 sibling, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-10 13:34 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, ke.vigouroux, 40671, Mattias Engdegård, Richard Stallman On 10.05.2020 06:13, Dmitry Gutov wrote: > The opposite of "mutable" is "immutable". Are quoted strings immutable? ^ string literals ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-10 3:13 ` Dmitry Gutov 2020-05-10 13:34 ` Dmitry Gutov @ 2020-05-10 17:29 ` Paul Eggert 2020-05-11 0:00 ` Michael Heerdegen 2020-05-11 0:44 ` Dmitry Gutov 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-10 17:29 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Richard Stallman [-- Attachment #1: Type: text/plain, Size: 2025 bytes --] On 5/9/20 8:13 PM, Dmitry Gutov wrote: > You start talking about objects that "should [not] change". And give an example > of an object that _cannot_ change. That's easily altered to also give an example of an object that should not change; see attached patch. > I could understand it if it was describing an existing type system of the > language, or implementation internals, but this is a purely imaginary type > system. objects.texi already talks about the Emacs Lisp type system and specifically mentions strings, conses, etc. as types. Even if one considers the Emacs Lisp type system to be "imaginary", it's reasonable to use the documentation's already-existing terminology here. > the list object didn't change, just an outside reference to its head was > created, The attached patch alters the example so that the list object does change (or at least tries to). > The opposite of "mutable" is "immutable". Are string literals immutable? They are > not. They might be mutable, and they might not be. The documentation deliberately doesn't say, because we don't want to document the details (they have changed in the past and are likely to change in the future). > Overall the phrase "that might be shared" is a good replacement. Why not keep to > it? Because it's not an accurate statement of the problem. The set of objects that might be shared differs from the set of objects that should not change. The Mutability node focuses on the latter set of objects, and gives the former as an example but it is not the only sort of object that should not change. > your new meaning of "mutable" doesn't seem indispensable. That bar is too high, as hardly anything in the manual is *indispensable*. Ihe notion of mutability is good to have in the manual, as it reduces confusion and helps in documentation elsewhere. That's good enough. I'm attaching two patches. The first are the changes mentioned above, and the second is a single patch that combines the first patch with the changes I previously proposed. [-- Attachment #2: 0001-Update-mutability-doc.patch --] [-- Type: text/x-patch, Size: 3026 bytes --] From f2f7cff7c72ca399ca49a50ceac660c3b0991d92 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sun, 10 May 2020 10:01:46 -0700 Subject: [PATCH] Update mutability doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * doc/lispref/objects.texi (Mutability): Revise in response to Dmitry Gutov’s comments (Bug#40671#420). --- doc/lispref/objects.texi | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index a0afadc2d7..7727a630dd 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -2379,26 +2379,37 @@ Mutability @section Mutability @cindex mutable objects - Some Lisp objects should never change. For example, you can create -a new number by calculating one, but you cannot modify the value of an -existing number. + Some Lisp objects should never change. For example, the Lisp +expression @code{"aaa"} yields a string, but you should not change +its contents. Indeed, some objects cannot be changed; for example, +although you can create a new number by calculating one, Lisp provides +no operation to change the value of an existing number. Other Lisp objects are @dfn{mutable}: it is safe to change their values via destructive operations involving side effects. For example, an existing marker can be changed by moving the marker to point to somewhere else. - Although numbers never change and all markers are mutable, a type -can be a hybrid with some members mutable and other members not. These -types include conses, vectors, strings, and symbols. For example, the string -literal @code{"aaa"} yields a string that should not be changed, whereas the -call @code{(make-string 3 ?a)} yields a mutable string that can be + Although numbers never change and all markers are mutable, +some types have members some of which are mutable and others not. These +types include conses, vectors, strings, and symbols. For example, +although @code{"aaa"} yields a string that should not be changed, +@code{(make-string 3 ?a)} yields a mutable string that can be changed via later calls to @code{aset}. A mutable object stops being mutable if it is part of an expression -that is evaluated. For example, in @code{(eval (list 'quote (list 1)))} -the list @code{(1)} was mutable when it was created, but it should not -be changed after it was part of an argument to @code{eval}. The +that is evaluated. For example: + +@example +(let* ((x (list 0.5)) + (y (eval (list 'quote x)))) + (setcar x 1.5) ;; The program should not do this. + y) +@end example + +@noindent +Although the list @code{(0.5)} was mutable when it was created, it should not +have been changed via @code{setcar} because it given to @code{eval}. The reverse does not occur: an object that should not be changed never becomes mutable afterwards. -- 2.17.1 [-- Attachment #3: 0001-Don-t-use-constant-for-values-you-shouldn-t-change.patch --] [-- Type: text/x-patch, Size: 18509 bytes --] From 1ddbbfd38c280822d1bed3c1281909fbfea1f54f Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sun, 10 May 2020 09:27:02 -0700 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20use=20=E2=80=9Cconstant?= =?UTF-8?q?=E2=80=9D=20for=20values=20you=20shouldn=E2=80=99t=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired by patch proposed by Dmitry Gutov (Bug#40671#393) and by his further comments (Bug#40671#420). * doc/lispintro/emacs-lisp-intro.texi (setcar): Don’t push mutability here. * doc/lispref/eval.texi (Self-Evaluating Forms, Quoting) (Backquote): * doc/lispref/lists.texi (Modifying Lists): * doc/lispref/objects.texi (Lisp Data Types, Mutability): * doc/lispref/sequences.texi (Array Functions, Vectors): * doc/lispref/strings.texi (String Basics, Modifying Strings): Don’t use the word “constant” to describe all values that a program should not change. * doc/lispref/objects.texi (Mutability): Rename from “Constants and Mutability”. All uses changed. In a footnote, contrast the Emacs behavior with that of Common Lisp, Python, etc. for clarity, and say the goal is to be nicer. Update mutability doc * doc/lispref/objects.texi (Mutability): Revise in response to Dmitry Gutov’s comments (Bug#40671#420). --- doc/lispintro/emacs-lisp-intro.texi | 5 +- doc/lispref/elisp.texi | 2 +- doc/lispref/eval.texi | 21 +++---- doc/lispref/lists.texi | 16 ++--- doc/lispref/objects.texi | 90 +++++++++++++++-------------- doc/lispref/sequences.texi | 25 ++++---- doc/lispref/strings.texi | 11 ++-- 7 files changed, 83 insertions(+), 87 deletions(-) diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index ea16d9ef15..46462162ca 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7317,8 +7317,6 @@ setcar works is to experiment. We will start with the @code{setcar} function. @need 1200 -@cindex constant lists -@cindex mutable lists First, we can make a list and then set the value of a variable to the list, using the @code{setq} special form. Because we intend to use @code{setcar} to change the list, this @code{setq} should not use the @@ -7327,8 +7325,7 @@ setcar tried to change part of the program while running it. Generally speaking an Emacs Lisp program's components should be constant (or unchanged) while the program is running. So we instead construct an -animal list that is @dfn{mutable} (or changeable) by using the -@code{list} function, as follows: +animal list by using the @code{list} function, as follows: @smallexample (setq animals (list 'antelope 'giraffe 'lion 'tiger)) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index bba1b63115..9a6796790c 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -297,7 +297,7 @@ Top * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. Programming Types diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index baddce4d9c..39f342a798 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -158,11 +158,11 @@ Self-Evaluating Forms @end group @end example - A self-evaluating form yields constant conses, vectors and strings, and you -should not attempt to modify their contents via @code{setcar}, @code{aset} or + A self-evaluating form yields a value that becomes part of the program, +and you should not try to modify it via @code{setcar}, @code{aset} or similar operations. The Lisp interpreter might unify the constants yielded by your program's self-evaluating forms, so that these -constants might share structure. @xref{Constants and Mutability}. +constants might share structure. @xref{Mutability}. It is common to write numbers, characters, strings, and even vectors in Lisp code, taking advantage of the fact that they self-evaluate. @@ -564,8 +564,8 @@ Quoting @defspec quote object This special form returns @var{object}, without evaluating it. -The returned value is a constant, and should not be modified. -@xref{Constants and Mutability}. +The returned value might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @end defspec @cindex @samp{'} for quoting @@ -608,9 +608,9 @@ Quoting Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)} both yield lists equal to @code{(+ 1 2)}, the former yields a -freshly-minted mutable list whereas the latter yields a constant list -built from conses that may be shared with other constants. -@xref{Constants and Mutability}. +freshly-minted mutable list whereas the latter yields a list +built from conses that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. Other quoting constructs include @code{function} (@pxref{Anonymous Functions}), which causes an anonymous lambda expression written in Lisp @@ -710,8 +710,9 @@ Backquote @end example If a subexpression of a backquote construct has no substitutions or -splices, it acts like @code{quote} in that it yields constant conses, -vectors and strings that should not be modified. +splices, it acts like @code{quote} in that it yields conses, +vectors and strings that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @node Eval @section Eval diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index fcaf4386b1..ae793d5e15 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -873,8 +873,8 @@ Modifying Lists operations because they change existing list structure. Destructive operations should be applied only to mutable lists, that is, lists constructed via @code{cons}, @code{list} or similar -operations. Lists created by quoting are constants and should not be -changed by destructive operations. @xref{Constants and Mutability}. +operations. Lists created by quoting are part of the program and +should not be changed by destructive operations. @xref{Mutability}. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -911,7 +911,7 @@ Setcar @example @group -(setq x (list 1 2)) ; @r{Create a mutable list.} +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -931,7 +931,7 @@ Setcar @example @group -;; @r{Create two mutable lists that are partly shared.} +;; @r{Create two lists that are partly shared.} (setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @@ -1022,11 +1022,11 @@ Setcdr @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} +(setcdr x '(4)) @result{} (4) @end group @group @@ -1135,11 +1135,11 @@ Rearrangement @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} +(nconc x '(4 5)) @result{} (1 2 3 4 5) @end group @group diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1d5b2c690f..7727a630dd 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -46,10 +46,6 @@ Lisp Data Types Lisp variables can only take on values of a certain type. @xref{Variables with Restricted Values}.) - Some Lisp objects are @dfn{constant}: their values should never change. -Others are @dfn{mutable}: their values can be changed via destructive -operations that involve side effects. - This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how to use these types can be found in later chapters. @@ -63,7 +59,7 @@ Lisp Data Types * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. @end menu @node Printed Representation @@ -2379,51 +2375,59 @@ Equality Predicates @end example @end defun -@node Constants and Mutability -@section Constants and Mutability -@cindex constants +@node Mutability +@section Mutability @cindex mutable objects - Some Lisp objects are constant: their values should never change -during a single execution of Emacs running well-behaved Lisp code. -For example, you can create a new integer by calculating one, but you -cannot modify the value of an existing integer. - - Other Lisp objects are mutable: it is safe to change their values -via destructive operations involving side effects. For example, an -existing marker can be changed by moving the marker to point to -somewhere else. - - Although all numbers are constants and all markers are -mutable, some types contain both constant and mutable members. These -types include conses, vectors, strings, and symbols. For example, the string -literal @code{"aaa"} yields a constant string, whereas the function -call @code{(make-string 3 ?a)} yields a mutable string that can be + Some Lisp objects should never change. For example, the Lisp +expression @code{"aaa"} yields a string, but you should not change +its contents. Indeed, some objects cannot be changed; for example, +although you can create a new number by calculating one, Lisp provides +no operation to change the value of an existing number. + + Other Lisp objects are @dfn{mutable}: it is safe to change their +values via destructive operations involving side effects. For +example, an existing marker can be changed by moving the marker to +point to somewhere else. + + Although numbers never change and all markers are mutable, +some types have members some of which are mutable and others not. These +types include conses, vectors, strings, and symbols. For example, +although @code{"aaa"} yields a string that should not be changed, +@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 part of an expression -that is evaluated. The reverse does not occur: constant objects -should stay constant. + A mutable object stops being mutable if it is part of an expression +that is evaluated. For example: + +@example +(let* ((x (list 0.5)) + (y (eval (list 'quote x)))) + (setcar x 1.5) ;; The program should not do this. + y) +@end example + +@noindent +Although the list @code{(0.5)} was mutable when it was created, it should not +have been changed via @code{setcar} because it given to @code{eval}. The +reverse does not occur: an object that should not be changed never +becomes mutable afterwards. 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 -resulting behavior is undefined: the Lisp interpreter might or might -not detect the error, and if it does not detect the error the -interpreter can behave unpredictably thereafter. Another way to put -this is that although mutable objects are safe to change and constant -variables reliably prevent attempts to change them, other constants -are not safely mutable: if a misbehaving program tries to change such a -constant then the constant's value might actually change, or the -program might crash or worse. This problem occurs -with types that have both constant and mutable members, and that have -mutators like @code{setcar} and @code{aset} that are valid on mutable -objects but hazardous on constants. - - When the same constant occurs multiple times in a program, the Lisp -interpreter might save time or space by reusing existing constants or -constant components. For example, @code{(eq "abc" "abc")} returns +If a program attempts to change other objects that should not be +changed, the resulting behavior is undefined: the Lisp interpreter +might signal an error, or it might crash or behave unpredictably in +other ways.@footnote{This is the behavior specified for languages like +Common Lisp and C, and it differs from the behavior of languages like +JavaScript and Python where an interpreter is required to signal an +error if a program attempts to change a constant. Ideally the Emacs +Lisp interpreter will evolve in latter direction.} + + When the same value appears multiple times in a program, the Lisp +interpreter might save time or space by reusing existing values or +their components. For example, @code{(eq "abc" "abc")} returns @code{t} if the interpreter creates only one instance of the string -constant @code{"abc"}, and returns @code{nil} if it creates two +literal @code{"abc"}, and returns @code{nil} if it creates two instances. Lisp programs should be written so that they work regardless of whether this optimization is in use. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1cb0d05cc7..91c3049f87 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ Sequence Functions @example @group -(setq bar (list 1 2)) ; @r{Create a mutable list.} +(setq bar (list 1 2)) @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} +(setq x (vector 'foo bar)) @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ Sequence Functions For the vector, it is even simpler because you don't need setq: @example -(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} +(setq x (copy-sequence [1 2 3 4])) @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -331,6 +331,7 @@ Sequence Functions Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly encouraged to treat strings as immutable even when they are mutable. +@xref{Mutability}. @end defun @@ -374,7 +375,7 @@ Sequence Functions @example @group -(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1229,7 @@ Array Functions @example @group -(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1238,7 @@ Array Functions @end group @group -;; @r{@code{copy-sequence} creates a mutable string.} +;; @r{@code{copy-sequence} copies the string to be modified later.} (setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @@ -1247,9 +1248,7 @@ Array Functions @end group @end example -The @var{array} should be mutable; that is, it should not be a constant, -such as the constants created via quoting or via self-evaluating forms. -@xref{Constants and Mutability}. +The @var{array} should be mutable. @xref{Mutability}. If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a @@ -1262,7 +1261,6 @@ Array Functions @example @group -;; @r{Create a mutable vector and then fill it with zeros.} (setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @@ -1271,7 +1269,6 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -;; @r{Create a mutable string and then fill it with "-".} (setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @@ -1310,8 +1307,8 @@ Vectors evaluation: the result of evaluating it is the same vector. This does not evaluate or even examine the elements of the vector. @xref{Self-Evaluating Forms}. Vectors written with square brackets -are constants and should not be modified via @code{aset} or other -destructive operations. @xref{Constants and Mutability}. +should not be modified via @code{aset} or other destructive +operations. @xref{Mutability}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index a4c9c2549c..70c3b3cf4b 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -49,10 +49,9 @@ String Basics Since strings are arrays, and therefore sequences as well, you can operate on them with the general array and sequence functions documented -in @ref{Sequences Arrays Vectors}. For example, you can access or -change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, you should not -try to change the contents of constant strings (@pxref{Modifying Strings}). +in @ref{Sequences Arrays Vectors}. For example, you can access +individual characters in a string using the function @code{aref} +(@pxref{Array Functions}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -382,9 +381,7 @@ Modifying Strings @cindex string modification You can alter the contents of a mutable string via operations -described in this section. However, you should not try to use these -operations to alter the contents of a constant string. -@xref{Constants and Mutability}. +described in this section. @xref{Mutability}. The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-10 17:29 ` Paul Eggert @ 2020-05-11 0:00 ` Michael Heerdegen 2020-05-11 0:26 ` Dmitry Gutov ` (2 more replies) 2020-05-11 0:44 ` Dmitry Gutov 1 sibling, 3 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 0:00 UTC (permalink / raw) To: Paul Eggert Cc: Mattias Engdegård, Dmitry Gutov, 40671, Richard Stallman, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > I'm attaching two patches. Thanks for the continued work on this, I appreciate the improvements and the general direction. I may have missed parts of the discussion recently, sorry if some comments are unsubstantial. So, a few questions about the patches: > + Although numbers never change and all markers are mutable, > +some types have members some of which are mutable and others not. These > +types include conses, vectors, strings, and symbols. For example, > +although @code{"aaa"} yields a string that should not be changed, > +@code{(make-string 3 ?a)} yields a mutable string that can be > changed via later calls to @code{aset}. Is this a good statement? The string read syntax, and the syntax for lists makes it easy to make such objects part of a program. But all classes of objects you call mutable can end up as part of a program. Are there any classes of "types" where all members are always mutable? Second point: you mix up objects vs. object evaluation. For conses you speak about the objects, for symbols about the binding (i.e. the result of the evaluation). Conses can also be evaluated (most programs are conses), but that's surely not what you want to describe. I would not say symbols are mutable. Symbols are constant AFAICT, their bindings are not (variables are not constant). > + A mutable object stops being mutable if it is part of an expression > +that is evaluated. For example: FWIW, I would feel better about the word "mutable" if you would introduce the term like "safely mutable", and then say that we call it just "mutable" in the following sections because this is shorter. Drew mentioned his dislike for the term "safe" AFAIR but I think "my Emacs won't crash if I follow this" vs. "it can crash" describes some kind of safety. Ignore if this comment is irrelevant because this is already done or treated otherwise. > + When the same value appears multiple times in a program, the Lisp > +interpreter might save time or space by reusing existing values or > +their components. For example, @code{(eq "abc" "abc")} returns I think we call "values" what evaluation of expressions yields, so values don't appear in a program (to be read). I don't know the backgrounds and when this can happen. Is it always the interpreter that does this mapping? "Same syntax" is not good as well: (eq (list 1 2 3) (list 1 2 3)) doesn't provoke the pitfall you warn about, but your wording doesn't make clear why the one case is ok and the other is not. Maybe it's again as simple as saying something about objects as being part of a program? Thanks again, Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 0:00 ` Michael Heerdegen @ 2020-05-11 0:26 ` Dmitry Gutov 2020-05-11 1:47 ` Drew Adams 2020-05-11 1:53 ` Paul Eggert 2 siblings, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-05-11 0:26 UTC (permalink / raw) To: Michael Heerdegen, Paul Eggert Cc: ke.vigouroux, 40671, Richard Stallman, Mattias Engdegård Thanks, Michael, +1 on your points, but this one especially: On 11.05.2020 03:00, Michael Heerdegen wrote: >> + A mutable object stops being mutable if it is part of an expression >> +that is evaluated. For example: > > FWIW, I would feel better about the word "mutable" if you would > introduce the term like "safely mutable", and then say that we call it > just "mutable" in the following sections because this is shorter. Drew > mentioned his dislike for the term "safe" AFAIR but I think "my Emacs > won't crash if I follow this" vs. "it can crash" describes some kind of > safety. "safely mutable" definitely sounds better to me. And while we might use the shorthand "mutable" in the corresponding section, while referring to this notion outside of it, it would be better to use the full two-word version. >> + When the same value appears multiple times in a program, the Lisp >> +interpreter might save time or space by reusing existing values or >> +their components. For example, @code{(eq "abc" "abc")} returns > > I think we call "values" what evaluation of expressions yields, so > values don't appear in a program (to be read). I don't know the > backgrounds and when this can happen. Is it always the interpreter that > does this mapping? > > "Same syntax" is not good as well: > > (eq (list 1 2 3) (list 1 2 3)) > > doesn't provoke the pitfall you warn about, but your wording doesn't > make clear why the one case is ok and the other is not. Maybe it's > again as simple as saying something about objects as being part of a > program? FWIW, CLtL seems to use a clunky term "similar as constants" for this. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 0:00 ` Michael Heerdegen 2020-05-11 0:26 ` Dmitry Gutov @ 2020-05-11 1:47 ` Drew Adams 2020-05-11 1:54 ` Dmitry Gutov 2020-05-11 2:56 ` Michael Heerdegen 2020-05-11 1:53 ` Paul Eggert 2 siblings, 2 replies; 170+ messages in thread From: Drew Adams @ 2020-05-11 1:47 UTC (permalink / raw) To: Michael Heerdegen, Paul Eggert Cc: ke.vigouroux, Dmitry Gutov, 40671, Richard Stallman, Mattias Engdegård > Symbols are constant AFAICT, their bindings > are not (variables are not constant). Their bindings as variables are not constant, except for keyword symbols, nil, and t (are there any others?). But are symbols otherwise constant, besides their values? Depends what you mean by "symbol", perhaps. Certainly you can change not only `symbol-value' but also `symbol-function' and `symbol-plist'. I don't see symbols as very constant. [Personally, as I suggested, I don't think the text about this gotcha should get down in the weeds about mutable/immutable anything. I think it should stay general, not try to catalog specific problems (e.g. strings, conses, whatever). It should show and explain a very simple example of what can happen with a quoted list, and then leave it at that. Maybe it should mention, as you said a while back, that there are the reader, interpreter, and byte compiler, when saying something about the problem in general. But I already said all this, and I said I was done here...] BTW, in Common Lisp you can even do nasty things like modify the `symbol-name' of a symbol. For that, CLTL2 says: "It is an extremely bad idea to modify a string being used as the print name of a symbol. Such a modification may tremendously confuse the function `read' and the package system." That's the _kind_ of somewhat vague gotcha description I think we should have. Enough to let users know they don't want to do it. > > + A mutable object stops being mutable if it is part of an > expression > > +that is evaluated. For example: > > FWIW, I would feel better about the word "mutable" if you would > introduce the term like "safely mutable", and then say that we call it > just "mutable" in the following sections because this is shorter. Drew > mentioned his dislike for the term "safe" AFAIR I don't recall saying that, but I may have. Not sure what's meant here. I objected to using "dangerous", as if the gotcha was generally hazardous to life. > but I think "my Emacs > won't crash if I follow this" vs. "it can crash" describes some kind of > safety. Ignore if this comment is irrelevant because this is already > done or treated otherwise. To me, the problem for users is not so much that Emacs can crash as it is that they may lose data. Or more likely (and worth mentioning, I think, as a motivator) that they might have a heck of a time trying to figure out why their code doesn't seem to behave as they expect. Seeing a quoted list in source code can make you think new list structure is created each time that code is run. Code "initializing" part of some list structure to a quoted list might give you the impression that that's what happens each time (e.g. each time a function that seems to do that gets called), but the same cons from a first evaluation (or reading) of that quoted list might remain in use for each invocation of the function. And if you at some point modify that cons then you might not get your apparent "initialization" to that quoted list each time the function's invoked. > > + When the same value appears multiple times ^^^^^ ^^^^^^^ > > +in a program, the Lisp interpreter might save > > +time or space by reusing existing values or ^^^^^^ > > +their components. > > I think we call "values" what evaluation of expressions yields, so > values don't appear in a program (to be read). I don't know the > backgrounds and when this can happen. Is it always the interpreter > that does this mapping? I think that text wasn't too bad, but I see your point. And it's especially not good to use "value" in the two different senses, as (1) something you see ("appears") in a source program and (2) a runtime value that results from reading, byte-compiling, or interpreting that source code. Maybe "object" or "Lisp object" instead of "value", for #2? (Note: I didn't read the full text. I'm just reacting to what was cited in your mail. Sorry.) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 1:47 ` Drew Adams @ 2020-05-11 1:54 ` Dmitry Gutov 2020-05-11 2:33 ` Drew Adams 2020-05-11 2:56 ` Michael Heerdegen 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-11 1:54 UTC (permalink / raw) To: Drew Adams, Michael Heerdegen, Paul Eggert Cc: ke.vigouroux, 40671, Richard Stallman, Mattias Engdegård On 11.05.2020 04:47, Drew Adams wrote: >> Drew >> mentioned his dislike for the term "safe" AFAIR > I don't recall saying that, but I may have. Not > sure what's meant here. I objected to using > "dangerous", as if the gotcha was generally > hazardous to life. Would "unsafe mutations" be better? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 1:54 ` Dmitry Gutov @ 2020-05-11 2:33 ` Drew Adams 0 siblings, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-05-11 2:33 UTC (permalink / raw) To: Dmitry Gutov, Michael Heerdegen, Paul Eggert Cc: ke.vigouroux, 40671, Richard Stallman, Mattias Engdegård > >> Drew mentioned his dislike for the term "safe" AFAIR > > > > I don't recall saying that, but I may have. Not > > sure what's meant here. I objected to using > > "dangerous", as if the gotcha was generally > > hazardous to life. > > Would "unsafe mutations" be better? I didn't really want to get into this with you guys. I just wanted to reply to Michael's message. But... I'd prefer that we speak of "modification", not "mutation". "Mutation" has a connotation of something happening on its own. If that were the case then we wouldn't be trying to tell people not to do something! I'm not a big fan of "safe" (or, especially, "dangerous"), unless it's about human safety (e.g. an airline maintenance manual). I'd prefer that we just tell users that if they do certain things then the behavior of their code _might not be what they expect_. Or that the behavior is "undefined". And let it go at that. What's important is to give them some idea of _what_ it is that we're telling them not to do. I don't have an example, but I think a simple quoted-list example can get the point across. And then you can say something about strings or whatever, if you like, without bothering with more examples. My advice: don't try to explain too well just what happens. See if you can get the general point across without any exhaustive rundown of a bunch of different cases or trying to be too exact. If a user understands that internal Lisp structures (objects) can get created by (1) the Lisp reader, (2) the interpreter, and (3) the byte compiler, and if s?he understands that what's seen in the source code does not necessarily correspond to when a corresponding Lisp object gets created, then s?he'll get it. Just when, and how many times does the source code of a quoted list result in a new cons? You can't really know. When it's read? byte-compiled? A new Lisp user thinks in terms of interpreted source code. Seeing a quoted list, s?he thinks that a new cons is created each time it's read, interpreted, or byte-compiled. But that may not (typically does not) happen. If you modify the cons that resulted from a source-code quoted list then that _same_ cons might be baked into the internal code thereafter. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 1:47 ` Drew Adams 2020-05-11 1:54 ` Dmitry Gutov @ 2020-05-11 2:56 ` Michael Heerdegen 2020-05-11 4:21 ` Drew Adams 1 sibling, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 2:56 UTC (permalink / raw) To: Drew Adams Cc: ke.vigouroux, Paul Eggert, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Drew Adams <drew.adams@oracle.com> writes: > But are symbols otherwise constant, besides their > values? Depends what you mean by "symbol", perhaps. > Certainly you can change not only `symbol-value' but > also `symbol-function' and `symbol-plist'. I don't > see symbols as very constant. Also makes sense, yes. > I think that text wasn't too bad, but I see your point. > > And it's especially not good to use "value" in the two > different senses, as (1) something you see ("appears") > in a source program and (2) a runtime value that results > from reading, byte-compiling, or interpreting that source > code. > > Maybe "object" or "Lisp object" instead of "value", for > #2? The term "value" is used all over the place in the manual for #2, so people are familiar with it, we need a better term for (1) instead I think. (info "(elisp) Equality Predicates") already uses the term "literal object" btw: The Emacs Lisp byte compiler may collapse identical literal objects, such as literal strings, into references to the same object, with the effect that the byte-compiled code will compare such objects as ‘eq’, while the interpreted version of the same code will not. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 2:56 ` Michael Heerdegen @ 2020-05-11 4:21 ` Drew Adams 2020-05-11 4:51 ` Michael Heerdegen 0 siblings, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-05-11 4:21 UTC (permalink / raw) To: Michael Heerdegen Cc: ke.vigouroux, Paul Eggert, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman (This ended up long and a bit off-topic; sorry. Hope it still helps.) > > And it's especially not good to use "value" in the two > > different senses, as (1) something you see ("appears") > > in a source program and (2) a runtime value that results > > from reading, byte-compiling, or interpreting that source > > code. > > > > Maybe "object" or "Lisp object" instead of "value", for > > #2? > > The term "value" is used all over the place in the manual for #2, so > people are familiar with it, we need a better term for (1) instead I > think. (info "(elisp) Equality Predicates") already uses the term > "literal object" btw: > > The Emacs Lisp byte compiler may collapse identical literal > objects, such as literal strings, into references to the same > object, with the effect that the byte-compiled code will compare > such objects as ‘eq’, while the interpreted version of the same > code will not. BTW, that node does NOT already contain that text. That paragraph is new for Emacs 27, which is not yet released. IOW, that text is _proposed_ for Emacs 27. But OK. That describes the problem as being about "literal objects". That's essentially the message we're discussing, I think, but it should be broadened beyond just the byte-compiler, I think. Where, if anywhere, does the manual define or describe "literal objects"? I don't think we want to be doing that, unless it's done carefully. For the message we're talking about, I'd say start by talking about source code: forms, sexps. Yes, the sexps that are problematic are, I suppose, what that text calls "literal objects". But I don't see that term defined anywhere. And it seems odd to me to talk about source-code thingies as "objects". Maybe the result of reading, or the result of some initial stage of byte-compiling or interpreting, is a "literal object", but is a source-code sexp a "literal object"? A "literal string" makes sense to me, as a string in source code ("..."). But "literal object" doesn't sound like a source-code thing. Perhaps that's what literal numbers, strings, etc. in source code are called now - "objects"? Sounds odd to me. Checking `i literal' in the Emacs 27 manual, I see no "literal object", but I do see "literal evaluation" and "literal in rx", where "literal" is used as a noun (in both cases presumably). However, the former index entry takes you to node `Self-Evaluating Forms', which never once uses the word "literal" (as adjective or noun) - it talks only about "forms", i.e., source code. That text looks OK. The index item seems wrong - you never get any text that tells you anything about "literal evaluation". This node, and index entry "literal evaluation" are in Emacs 26 (and probably earlier). [Index entry "literal in rx" takes you to node `Rx Constructs', where you find `(literal EXPR)', which is about matching a "literal string". To me, "literal string" is clear enough, and I think of it as both a source-code thing (text) and as a Lisp object (after reading the text, for example). This node is new for Emacs 27.] Searching the Emacs 27 Elisp manual for "literal" I see that there is another occurrence of "literal object", also in a node that is new for release 27, `pcase Macro'. There too the term "literal object"is totally unexplained: "Matches if EXPL equals the literal object. This is a special case of ‘'VAL’, above, possible because literal objects of these types are self-quoting." (The "possible because..." is not correct English, and I don't know what it's trying to say. Maybe "possibly because..." was meant. Or maybe what was meant was to end a sentence after "above" and start a new sentence with "This is possible because...".) And again, in another new-to-Emacs-27 node, `Backquote Patterns', I see "literal object": "Matches if the corresponding element of EXPVAL is ‘equal’ to the specified literal object." And again, the term is totally unexplained. (That node also has "literal symbol", which, like "literal string" doesn't shock me. It is "literal object" that I find odd.) Both Emacs 27 and 26, node `Mode-Specific Indent', mention "a literal value (usually zero)". That's OK, I guess, but I think it's untrue. I think what's meant is just "a number (usually zero)". There's nothing literal about it. Node `Rx Constructs' of Emacs 27 introduces "Literals" (noun) as forms (source-code sexps), and shows that they can be strings or chars. I don't have a problem with that. Node `Rx Functions' says "if `literal' or `regexp' forms are used", and I guess that's referring to the forms `(literal...)' and `(regexp...)' introduced in node `Rx Constructs'. And it refers to "string literals". All of that's OK. Node `Extending Rx' mentions "a list literal". Again, like string literal, char literal, etc., this isn't introduced anywhere that I can see, but that's OK - use of "literal" as a noun in such cases clearly means the same as "literal string" etc. Node `Module Initialization' is another new one for Emacs 27, and another place where "literal" is used as a noun: "number literal". Again, no problem for me with that (like "string literal"). All other occurrences of "literal" in the manual are about literal chars, finding a file literally, displaying or matching text literally, or replacing literal text. No problem there, and nothing new there. In sum, "literal object" is nowhere defined, described, or explained. And "object" sounds wrong, to me, when referring to source-code text. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 4:21 ` Drew Adams @ 2020-05-11 4:51 ` Michael Heerdegen 2020-05-11 6:28 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 4:51 UTC (permalink / raw) To: Drew Adams Cc: ke.vigouroux, Paul Eggert, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Drew Adams <drew.adams@oracle.com> writes: > In sum, "literal object" is nowhere defined, > described, or explained. And "object" sounds > wrong, to me, when referring to source-code text. Yes, it's vague. Maybe the place I cited should formulated otherwise, since we didn't use the term for the "no no" objects, for reasons. BTW (also @Paul) there are some places (five or so) in Elisp source files that look like (nconc '(x y z) (get-some-list)) Should they be rewritten? Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 4:51 ` Michael Heerdegen @ 2020-05-11 6:28 ` Paul Eggert 2020-05-11 13:57 ` Noam Postavsky ` (3 more replies) 0 siblings, 4 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-11 6:28 UTC (permalink / raw) To: Michael Heerdegen, Drew Adams Cc: ke.vigouroux, Dmitry Gutov, 40671, Richard Stallman, Mattias Engdegård [-- Attachment #1: Type: text/plain, Size: 288 bytes --] On 5/10/20 9:51 PM, Michael Heerdegen wrote: > BTW (also @Paul) there are some places (five or so) in Elisp source > files that look like > > (nconc '(x y z) (get-some-list)) > > Should they be rewritten? Yes, of course. Does the attached diff (against master) match what you found? [-- Attachment #2: nconc.diff --] [-- Type: text/x-patch, Size: 6959 bytes --] diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 4f72251aed..fd6c6fe1ad 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1509,14 +1509,13 @@ byte-compile-side-effect-and-error-free-ops byte-current-buffer byte-stack-ref)) (defconst byte-compile-side-effect-free-ops - (nconc - '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref - byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1 - byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate - byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax - byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt - byte-member byte-assq byte-quo byte-rem byte-substring) - byte-compile-side-effect-and-error-free-ops)) + `(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref + byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1 + byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate + byte-plus byte-max byte-min byte-mult byte-char-after byte-char-syntax + byte-buffer-substring byte-string= byte-string< byte-nthcdr byte-elt + byte-member byte-assq byte-quo byte-rem byte-substring + ,@byte-compile-side-effect-and-error-free-ops)) ;; This crock is because of the way DEFVAR_BOOL variables work. ;; Consider the code diff --git a/lisp/frameset.el b/lisp/frameset.el index 10c6914f52..5850561928 100644 --- a/lisp/frameset.el +++ b/lisp/frameset.el @@ -396,17 +396,17 @@ frameset-prop ;; or, if you're only changing a few items, ;; ;; (defvar my-filter-alist -;; (nconc '((my-param1 . :never) -;; (my-param2 . my-filtering-function)) -;; frameset-filter-alist) +;; `((my-param1 . :never) +;; (my-param2 . my-filtering-function) +;; ,@frameset-filter-alist) ;; "My brief customized parameter filter alist.") ;; ;; and pass it to the FILTER arg of the save/restore functions, ;; ALWAYS taking care of not modifying the original lists; if you're ;; going to do any modifying of my-filter-alist, please use ;; -;; (nconc '((my-param1 . :never) ...) -;; (copy-sequence frameset-filter-alist)) +;; `(((my-param1 . :never) ...) +;; ,@(copy-sequence frameset-filter-alist)) ;; ;; One thing you shouldn't forget is that they are alists, so searching ;; in them is sequential. If you just want to change the default of @@ -445,39 +445,38 @@ frameset-session-filter-alist ;;;###autoload (defvar frameset-persistent-filter-alist - (nconc - '((background-color . frameset-filter-sanitize-color) - (buffer-list . :never) - (buffer-predicate . :never) - (buried-buffer-list . :never) - ;; Don't save the 'client' parameter to avoid that a subsequent - ;; `save-buffers-kill-terminal' in a non-client session barks at - ;; the user (Bug#29067). - (client . :never) - (delete-before . :never) - (font . frameset-filter-font-param) - ;; Don't save font-backend because we cannot guarantee the new - ;; session will support the saved backend anyway. (Bug#38442) - (font-backend . :never) - (foreground-color . frameset-filter-sanitize-color) - (frameset--text-pixel-height . :save) - (frameset--text-pixel-width . :save) - (fullscreen . frameset-filter-shelve-param) - (GUI:font . frameset-filter-unshelve-param) - (GUI:fullscreen . frameset-filter-unshelve-param) - (GUI:height . frameset-filter-unshelve-param) - (GUI:width . frameset-filter-unshelve-param) - (height . frameset-filter-shelve-param) - (outer-window-id . :never) - (parent-frame . :never) - (parent-id . :never) - (mouse-wheel-frame . :never) - (tty . frameset-filter-tty-to-GUI) - (tty-type . frameset-filter-tty-to-GUI) - (width . frameset-filter-shelve-param) - (window-id . :never) - (window-system . :never)) - frameset-session-filter-alist) + `((background-color . frameset-filter-sanitize-color) + (buffer-list . :never) + (buffer-predicate . :never) + (buried-buffer-list . :never) + ;; Don't save the 'client' parameter to avoid that a subsequent + ;; `save-buffers-kill-terminal' in a non-client session barks at + ;; the user (Bug#29067). + (client . :never) + (delete-before . :never) + (font . frameset-filter-font-param) + ;; Don't save font-backend because we cannot guarantee the new + ;; session will support the saved backend anyway. (Bug#38442) + (font-backend . :never) + (foreground-color . frameset-filter-sanitize-color) + (frameset--text-pixel-height . :save) + (frameset--text-pixel-width . :save) + (fullscreen . frameset-filter-shelve-param) + (GUI:font . frameset-filter-unshelve-param) + (GUI:fullscreen . frameset-filter-unshelve-param) + (GUI:height . frameset-filter-unshelve-param) + (GUI:width . frameset-filter-unshelve-param) + (height . frameset-filter-shelve-param) + (outer-window-id . :never) + (parent-frame . :never) + (parent-id . :never) + (mouse-wheel-frame . :never) + (tty . frameset-filter-tty-to-GUI) + (tty-type . frameset-filter-tty-to-GUI) + (width . frameset-filter-shelve-param) + (window-id . :never) + (window-system . :never) + ,@frameset-session-filter-alist) "Parameters to filter for persistent framesets. DO NOT MODIFY. See `frameset-filter-alist' for a full description.") diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index 6f367692dd..595df607f5 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -1501,9 +1501,9 @@ gnus-summary-mode-line-format-alist ;; This is here rather than in gnus-art for compilation reasons. (defvar gnus-article-mode-line-format-alist - (nconc '((?w (gnus-article-wash-status) ?s) - (?m (gnus-article-mime-part-status) ?s)) - gnus-summary-mode-line-format-alist)) + (nconc `((?w (gnus-article-wash-status) ?s) + (?m (gnus-article-mime-part-status) ?s) + ,@gnus-summary-mode-line-format-alist))) (defvar gnus-last-search-regexp nil "Default regexp for article search command.") ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 6:28 ` Paul Eggert @ 2020-05-11 13:57 ` Noam Postavsky 2020-05-11 22:36 ` Michael Heerdegen 2020-05-11 22:30 ` Michael Heerdegen ` (2 subsequent siblings) 3 siblings, 1 reply; 170+ messages in thread From: Noam Postavsky @ 2020-05-11 13:57 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, Richard Stallman, Michael Heerdegen, Mattias Engdegård, Dmitry Gutov, 40671 Paul Eggert <eggert@cs.ucla.edu> writes: > (defvar gnus-article-mode-line-format-alist > - (nconc '((?w (gnus-article-wash-status) ?s) > - (?m (gnus-article-mime-part-status) ?s)) > - gnus-summary-mode-line-format-alist)) > + (nconc `((?w (gnus-article-wash-status) ?s) > + (?m (gnus-article-mime-part-status) ?s) > + ,@gnus-summary-mode-line-format-alist))) You meant to remove the nconc call too, right? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 13:57 ` Noam Postavsky @ 2020-05-11 22:36 ` Michael Heerdegen 0 siblings, 0 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 22:36 UTC (permalink / raw) To: Noam Postavsky Cc: ke.vigouroux, Paul Eggert, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Noam Postavsky <npostavs@gmail.com> writes: > Paul Eggert <eggert@cs.ucla.edu> writes: > > > (defvar gnus-article-mode-line-format-alist > > - (nconc '((?w (gnus-article-wash-status) ?s) > > - (?m (gnus-article-mime-part-status) ?s)) > > - gnus-summary-mode-line-format-alist)) > > + (nconc `((?w (gnus-article-wash-status) ?s) > > + (?m (gnus-article-mime-part-status) ?s) > > + ,@gnus-summary-mode-line-format-alist))) > > You meant to remove the nconc call too, right? That, and, the code still makes literal lists to alist entries. If you modify these associations, you modify these literal lists. I wonder how many of such uses of backquote expressions used to construct alists are scattered throughout the Emacs code. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 6:28 ` Paul Eggert 2020-05-11 13:57 ` Noam Postavsky @ 2020-05-11 22:30 ` Michael Heerdegen 2020-05-12 3:20 ` Richard Stallman [not found] ` <05BEF593-F16A-4DEE-98BC-653221F1F9EE@acm.org> 3 siblings, 0 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 22:30 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Paul Eggert <eggert@cs.ucla.edu> writes: > Yes, of course. Does the attached diff (against master) match what you > found? Yes, I think so. Thanks, Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 6:28 ` Paul Eggert 2020-05-11 13:57 ` Noam Postavsky 2020-05-11 22:30 ` Michael Heerdegen @ 2020-05-12 3:20 ` Richard Stallman 2020-05-12 4:24 ` Michael Heerdegen [not found] ` <05BEF593-F16A-4DEE-98BC-653221F1F9EE@acm.org> 3 siblings, 1 reply; 170+ messages in thread From: Richard Stallman @ 2020-05-12 3:20 UTC (permalink / raw) To: Paul Eggert; +Cc: ke.vigouroux, 40671, michael_heerdegen, mattiase, dgutov [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] Would someone like to search all our Lisp sources for "(nconc '" and check every occurrence? -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-12 3:20 ` Richard Stallman @ 2020-05-12 4:24 ` Michael Heerdegen 2020-05-13 3:57 ` Richard Stallman 0 siblings, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-05-12 4:24 UTC (permalink / raw) To: Richard Stallman; +Cc: ke.vigouroux, Paul Eggert, 40671, mattiase, dgutov Richard Stallman <rms@gnu.org> writes: > Would someone like to search all our Lisp sources for "(nconc '" and > check every occurrence? Paul and I found the same matches with probably different methods - so I think this already has been done. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-12 4:24 ` Michael Heerdegen @ 2020-05-13 3:57 ` Richard Stallman 2020-05-13 5:05 ` Michael Heerdegen 0 siblings, 1 reply; 170+ messages in thread From: Richard Stallman @ 2020-05-13 3:57 UTC (permalink / raw) To: Michael Heerdegen; +Cc: mattiase, ke.vigouroux, eggert, 40671, dgutov [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > Paul and I found the same matches with probably different methods - so I > think this already has been done. When you found them, did you fix them? -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-13 3:57 ` Richard Stallman @ 2020-05-13 5:05 ` Michael Heerdegen 2020-05-14 5:14 ` Richard Stallman 0 siblings, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-05-13 5:05 UTC (permalink / raw) To: Richard Stallman; +Cc: mattiase, ke.vigouroux, eggert, 40671, dgutov Richard Stallman <rms@gnu.org> writes: > When you found them, did you fix them? Paul has already proposed a patch, I guess he will install it later (maybe after caring about the remarks by Noam and me). Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-13 5:05 ` Michael Heerdegen @ 2020-05-14 5:14 ` Richard Stallman 0 siblings, 0 replies; 170+ messages in thread From: Richard Stallman @ 2020-05-14 5:14 UTC (permalink / raw) To: Michael Heerdegen; +Cc: ke.vigouroux, mattiase, eggert, 40671, dgutov [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > Paul has already proposed a patch, I guess he will install it later > (maybe after caring about the remarks by Noam and me). Thank you, and Paul. -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
[parent not found: <05BEF593-F16A-4DEE-98BC-653221F1F9EE@acm.org>]
* bug#40671: [DOC] modify literal objects [not found] ` <05BEF593-F16A-4DEE-98BC-653221F1F9EE@acm.org> @ 2020-05-17 0:11 ` Paul Eggert 2020-05-17 9:43 ` Mattias Engdegård 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-17 0:11 UTC (permalink / raw) To: Mattias Engdegård; +Cc: Michael Heerdegen, 40671 [-- Attachment #1: Type: text/plain, Size: 670 bytes --] On 5/11/20 2:29 AM, Mattias Engdegård wrote: > As an experiment, I added an immutable cons type some time ago and found these and more. The attachment contains some of the adjustments made at the time. This isn't complete; I never got to a full bootstrap, for unrelated reasons. Thanks for sending that patch. Even if incomplete, it's better to not try to modify constants so I installed the attached into master; it's derived from your patch and supersedes my earlier (typo-containing) patch about nconc. > By the way: Is there any reason you prefer `(a b c ,@tail) to (append '(a b c) tail)? No, I just wasn't thinking. The attached patch uses 'append'. [-- Attachment #2: 0001-Don-t-attempt-to-modify-constant-conses.txt --] [-- Type: text/plain, Size: 14483 bytes --] From aed11100f8056804d2e438fc4e793dc099d0e06f Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sat, 16 May 2020 17:04:15 -0700 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20attempt=20to=20modify=20constan?= =?UTF-8?q?t=20conses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From a patch privately suggested by Mattias Engdegård on 2020-05-11 in a followup to Bug#40671. * admin/charsets/cp51932.awk: * admin/charsets/eucjp-ms.awk: Generate code that does not modify constant conses. * doc/misc/emacs-mime.texi (Encoding Customization): * lisp/emacs-lisp/byte-opt.el (byte-compile-side-effect-free-ops): * lisp/frameset.el (frameset-persistent-filter-alist): * lisp/gnus/gnus-sum.el (gnus-article-mode-line-format-alist): Use append instead of nconc. * lisp/language/japanese.el (japanese-ucs-cp932-to-jis-map) (jisx0213-to-unicode): Use mapcar instead of mapc. * lisp/language/lao-util.el (lao-transcription-consonant-alist) (lao-transcription-vowel-alist): * lisp/language/tibetan.el (tibetan-subjoined-transcription-alist): Use copy-sequence. * test/src/fns-tests.el (fns-tests-nreverse): (fns-tests-sort, fns-tests-collate-sort) (fns-tests-string-version-lessp, fns-tests-mapcan): Use copy-sequence, vector, and list. --- admin/charsets/cp51932.awk | 13 +++++++------ admin/charsets/eucjp-ms.awk | 14 ++++++++------ doc/misc/emacs-mime.texi | 2 +- lisp/emacs-lisp/byte-opt.el | 2 +- lisp/frameset.el | 12 ++++++------ lisp/gnus/gnus-sum.el | 6 +++--- lisp/language/japanese.el | 10 +++++----- lisp/language/lao-util.el | 16 ++++++++++------ lisp/language/tibetan.el | 8 +++++--- test/src/fns-tests.el | 34 +++++++++++++++++----------------- 10 files changed, 63 insertions(+), 54 deletions(-) diff --git a/admin/charsets/cp51932.awk b/admin/charsets/cp51932.awk index 6aac98815b..c355509524 100644 --- a/admin/charsets/cp51932.awk +++ b/admin/charsets/cp51932.awk @@ -43,13 +43,14 @@ BEGIN { END { print ")))"; - print " (mapc #'(lambda (x)"; - print " (setcar x (decode-char 'japanese-jisx0208 (car x))))"; - print " map)"; + print " (setq map (mapcar (lambda (x)"; + print " (cons (decode-char 'japanese-jisx0208 (car x))"; + print " (cdr x)))"; + print " map))"; print " (define-translation-table 'cp51932-decode map)"; - print " (mapc #'(lambda (x)"; - print " (let ((tmp (car x)))"; - print " (setcar x (cdr x)) (setcdr x tmp)))"; + print " (mapc (lambda (x)"; + print " (let ((tmp (car x)))"; + print " (setcar x (cdr x)) (setcdr x tmp)))"; print " map)"; print " (define-translation-table 'cp51932-encode map))"; print ""; diff --git a/admin/charsets/eucjp-ms.awk b/admin/charsets/eucjp-ms.awk index 0c9f94d0f4..f6a6748ce5 100644 --- a/admin/charsets/eucjp-ms.awk +++ b/admin/charsets/eucjp-ms.awk @@ -93,15 +93,17 @@ function write_entry (unicode) { END { print ")))"; - print " (mapc #'(lambda (x)"; + print " (setq map"; + print " (mapcar"; + print " (lambda (x)"; print " (let ((code (logand (car x) #x7F7F)))"; print " (if (integerp (cdr x))"; - print " (setcar x (decode-char 'japanese-jisx0208 code))"; - print " (setcar x (decode-char 'japanese-jisx0212 code))"; - print " (setcdr x (cadr x)))))"; - print " map)"; + print " (cons (decode-char 'japanese-jisx0208 code) (cdr x))"; + print " (cons (decode-char 'japanese-jisx0212 code)" + print " (cadr x)))))"; + print " map))"; print " (define-translation-table 'eucjp-ms-decode map)"; - print " (mapc #'(lambda (x)"; + print " (mapc (lambda (x)"; print " (let ((tmp (car x)))"; print " (setcar x (cdr x)) (setcdr x tmp)))"; print " map)"; diff --git a/doc/misc/emacs-mime.texi b/doc/misc/emacs-mime.texi index 42a7750b9a..2f38dcd495 100644 --- a/doc/misc/emacs-mime.texi +++ b/doc/misc/emacs-mime.texi @@ -917,7 +917,7 @@ Encoding Customization @lisp (add-to-list 'gnus-newsgroup-variables 'mm-coding-system-priorities) (setq gnus-parameters - (nconc + (append ;; Some charsets are just examples! '(("^cn\\." ;; Chinese (mm-coding-system-priorities diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 4f72251aed..62b82e4f32 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1509,7 +1509,7 @@ byte-compile-side-effect-and-error-free-ops byte-current-buffer byte-stack-ref)) (defconst byte-compile-side-effect-free-ops - (nconc + (append '(byte-varref byte-nth byte-memq byte-car byte-cdr byte-length byte-aref byte-symbol-value byte-get byte-concat2 byte-concat3 byte-sub1 byte-add1 byte-eqlsign byte-gtr byte-lss byte-leq byte-geq byte-diff byte-negate diff --git a/lisp/frameset.el b/lisp/frameset.el index 10c6914f52..0462d776c0 100644 --- a/lisp/frameset.el +++ b/lisp/frameset.el @@ -396,17 +396,17 @@ frameset-prop ;; or, if you're only changing a few items, ;; ;; (defvar my-filter-alist -;; (nconc '((my-param1 . :never) -;; (my-param2 . my-filtering-function)) -;; frameset-filter-alist) +;; (append '((my-param1 . :never) +;; (my-param2 . my-filtering-function)) +;; frameset-filter-alist) ;; "My brief customized parameter filter alist.") ;; ;; and pass it to the FILTER arg of the save/restore functions, ;; ALWAYS taking care of not modifying the original lists; if you're ;; going to do any modifying of my-filter-alist, please use ;; -;; (nconc '((my-param1 . :never) ...) -;; (copy-sequence frameset-filter-alist)) +;; (append '((my-param1 . :never) ...) +;; (copy-sequence frameset-filter-alist)) ;; ;; One thing you shouldn't forget is that they are alists, so searching ;; in them is sequential. If you just want to change the default of @@ -445,7 +445,7 @@ frameset-session-filter-alist ;;;###autoload (defvar frameset-persistent-filter-alist - (nconc + (append '((background-color . frameset-filter-sanitize-color) (buffer-list . :never) (buffer-predicate . :never) diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el index 6f367692dd..341f04ad77 100644 --- a/lisp/gnus/gnus-sum.el +++ b/lisp/gnus/gnus-sum.el @@ -1501,9 +1501,9 @@ gnus-summary-mode-line-format-alist ;; This is here rather than in gnus-art for compilation reasons. (defvar gnus-article-mode-line-format-alist - (nconc '((?w (gnus-article-wash-status) ?s) - (?m (gnus-article-mime-part-status) ?s)) - gnus-summary-mode-line-format-alist)) + (append '((?w (gnus-article-wash-status) ?s) + (?m (gnus-article-mime-part-status) ?s)) + gnus-summary-mode-line-format-alist)) (defvar gnus-last-search-regexp nil "Default regexp for article search command.") diff --git a/lisp/language/japanese.el b/lisp/language/japanese.el index d77efa48c9..9a99245dfd 100644 --- a/lisp/language/japanese.el +++ b/lisp/language/japanese.el @@ -82,9 +82,7 @@ 'iso-2022-jp-2 (#x00A6 . #xFFE4) ; BROKEN LINE FULLWIDTH BROKEN LINE ))) (define-translation-table 'japanese-ucs-jis-to-cp932-map map) - (mapc #'(lambda (x) (let ((tmp (car x))) - (setcar x (cdr x)) (setcdr x tmp))) - map) + (setq map (mapcar (lambda (x) (cons (cdr x) (car x))) map)) (define-translation-table 'japanese-ucs-cp932-to-jis-map map)) ;; U+2014 (EM DASH) vs U+2015 (HORIZONTAL BAR) @@ -241,8 +239,10 @@ 'shift_jis-2004 (#x2b65 . [#x02E9 #x02E5]) (#x2b66 . [#x02E5 #x02E9]))) table) - (dolist (elt map) - (setcar elt (decode-char 'japanese-jisx0213-1 (car elt)))) + (setq map + (mapcar (lambda (x) (cons (decode-char 'japanese-jisx0213-1 (car x)) + (cdr x))) + map)) (setq table (make-translation-table-from-alist map)) (define-translation-table 'jisx0213-to-unicode table) (define-translation-table 'unicode-to-jisx0213 diff --git a/lisp/language/lao-util.el b/lisp/language/lao-util.el index a20aecee42..fa4c2f7f89 100644 --- a/lisp/language/lao-util.el +++ b/lisp/language/lao-util.el @@ -183,7 +183,9 @@ lao-compose-string ;; Semi-vowel-sign-lo and lower vowels are put under the letter. (defconst lao-transcription-consonant-alist - (sort '(;; single consonants + (sort + (copy-sequence + '(;; single consonants ("k" . "ກ") ("kh" . "ຂ") ("qh" . "ຄ") @@ -223,14 +225,16 @@ lao-transcription-consonant-alist ("hy" . ["ຫຍ"]) ("hn" . ["ຫນ"]) ("hm" . ["ຫມ"]) - ) - (function (lambda (x y) (> (length (car x)) (length (car y))))))) + )) + (lambda (x y) (> (length (car x)) (length (car y)))))) (defconst lao-transcription-semi-vowel-alist '(("r" . "ຼ"))) (defconst lao-transcription-vowel-alist - (sort '(("a" . "ະ") + (sort + (copy-sequence + '(("a" . "ະ") ("ar" . "າ") ("i" . "ິ") ("ii" . "ີ") @@ -257,8 +261,8 @@ lao-transcription-vowel-alist ("ai" . "ໄ") ("ei" . "ໃ") ("ao" . ["ເົາ"]) - ("aM" . "ຳ")) - (function (lambda (x y) (> (length (car x)) (length (car y))))))) + ("aM" . "ຳ"))) + (lambda (x y) (> (length (car x)) (length (car y)))))) ;; Maa-sakod is put at the tail. (defconst lao-transcription-maa-sakod-alist diff --git a/lisp/language/tibetan.el b/lisp/language/tibetan.el index d31cd5cd52..bbd4729f6c 100644 --- a/lisp/language/tibetan.el +++ b/lisp/language/tibetan.el @@ -326,7 +326,9 @@ tibetan-precomposed-transcription-alist (defconst tibetan-subjoined-transcription-alist - (sort '(("+k" . "ྐ") + (sort + (copy-sequence + '(("+k" . "ྐ") ("+kh" . "ྑ") ("+g" . "ྒ") ("+gh" . "ྒྷ") @@ -371,8 +373,8 @@ tibetan-subjoined-transcription-alist ("+W" . "ྺ") ;; fixed form subscribed WA ("+Y" . "ྻ") ;; fixed form subscribed YA ("+R" . "ྼ") ;; fixed form subscribed RA - ) - (lambda (x y) (> (length (car x)) (length (car y)))))) + )) + (lambda (x y) (> (length (car x)) (length (car y)))))) ;;; ;;; alist for Tibetan base consonant <-> subjoined consonant conversion. diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el index c6ceae4a00..b65543a64b 100644 --- a/test/src/fns-tests.el +++ b/test/src/fns-tests.el @@ -49,21 +49,21 @@ fns-tests-nreverse (should-error (nreverse)) (should-error (nreverse 1)) (should-error (nreverse (make-char-table 'foo))) - (should (equal (nreverse "xyzzy") "yzzyx")) - (let ((A [])) + (should (equal (nreverse (copy-sequence "xyzzy")) "yzzyx")) + (let ((A (vector))) (nreverse A) (should (equal A []))) - (let ((A [0])) + (let ((A (vector 0))) (nreverse A) (should (equal A [0]))) - (let ((A [1 2 3 4])) + (let ((A (vector 1 2 3 4))) (nreverse A) (should (equal A [4 3 2 1]))) - (let ((A [1 2 3 4])) + (let ((A (vector 1 2 3 4))) (nreverse A) (nreverse A) (should (equal A [1 2 3 4]))) - (let* ((A [1 2 3 4]) + (let* ((A (vector 1 2 3 4)) (B (nreverse (nreverse A)))) (should (equal A B)))) @@ -146,13 +146,13 @@ fns-tests-collate-strings ;; Invalid UTF-8 sequences shall be indicated. How to create such strings? (ert-deftest fns-tests-sort () - (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y))) + (should (equal (sort (list 9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y))) '(-1 2 3 4 5 5 7 8 9))) - (should (equal (sort '(9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y))) + (should (equal (sort (list 9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y))) '(9 8 7 5 5 4 3 2 -1))) - (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (< x y))) + (should (equal (sort (vector 9 5 2 -1 5 3 8 7 4) (lambda (x y) (< x y))) [-1 2 3 4 5 5 7 8 9])) - (should (equal (sort '[9 5 2 -1 5 3 8 7 4] (lambda (x y) (> x y))) + (should (equal (sort (vector 9 5 2 -1 5 3 8 7 4) (lambda (x y) (> x y))) [9 8 7 5 5 4 3 2 -1])) (should (equal (sort @@ -172,7 +172,7 @@ fns-tests-collate-sort ;; Punctuation and whitespace characters are relevant for POSIX. (should (equal - (sort '("11" "12" "1 1" "1 2" "1.1" "1.2") + (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") (lambda (a b) (string-collate-lessp a b "POSIX"))) '("1 1" "1 2" "1.1" "1.2" "11" "12"))) ;; Punctuation and whitespace characters are not taken into account @@ -180,7 +180,7 @@ fns-tests-collate-sort (when (eq system-type 'windows-nt) (should (equal - (sort '("11" "12" "1 1" "1 2" "1.1" "1.2") + (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") (lambda (a b) (let ((w32-collate-ignore-punctuation t)) (string-collate-lessp @@ -190,7 +190,7 @@ fns-tests-collate-sort ;; Diacritics are different letters for POSIX, they sort lexicographical. (should (equal - (sort '("Ævar" "Agustín" "Adrian" "Eli") + (sort (list "Ævar" "Agustín" "Adrian" "Eli") (lambda (a b) (string-collate-lessp a b "POSIX"))) '("Adrian" "Agustín" "Eli" "Ævar"))) ;; Diacritics are sorted between similar letters for other locales, @@ -198,7 +198,7 @@ fns-tests-collate-sort (when (eq system-type 'windows-nt) (should (equal - (sort '("Ævar" "Agustín" "Adrian" "Eli") + (sort (list "Ævar" "Agustín" "Adrian" "Eli") (lambda (a b) (let ((w32-collate-ignore-punctuation t)) (string-collate-lessp @@ -212,7 +212,7 @@ fns-tests-string-version-lessp (should (not (string-version-lessp "foo20000.png" "foo12.png"))) (should (string-version-lessp "foo.png" "foo2.png")) (should (not (string-version-lessp "foo2.png" "foo.png"))) - (should (equal (sort '("foo12.png" "foo2.png" "foo1.png") + (should (equal (sort (list "foo12.png" "foo2.png" "foo1.png") 'string-version-lessp) '("foo1.png" "foo2.png" "foo12.png"))) (should (string-version-lessp "foo2" "foo1234")) @@ -432,9 +432,9 @@ fns-tests-mapcan (should-error (mapcan)) (should-error (mapcan #'identity)) (should-error (mapcan #'identity (make-char-table 'foo))) - (should (equal (mapcan #'list '(1 2 3)) '(1 2 3))) + (should (equal (mapcan #'list (list 1 2 3)) '(1 2 3))) ;; `mapcan' is destructive - (let ((data '((foo) (bar)))) + (let ((data (list (list 'foo) (list 'bar)))) (should (equal (mapcan #'identity data) '(foo bar))) (should (equal data '((foo bar) (bar)))))) -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 0:11 ` Paul Eggert @ 2020-05-17 9:43 ` Mattias Engdegård 2020-05-17 16:38 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Mattias Engdegård @ 2020-05-17 9:43 UTC (permalink / raw) To: Paul Eggert; +Cc: Michael Heerdegen, 40671 17 maj 2020 kl. 02.11 skrev Paul Eggert <eggert@cs.ucla.edu>: > Thanks for sending that patch. Even if incomplete, it's better to not try to > modify constants so I installed the attached into master; it's derived from your > patch and supersedes my earlier (typo-containing) patch about nconc. Thank you, and your resulting patch looks all right. As an extra check, I verified that the AWK-generated files result in the same tables. The follow-up change reducing string and vector literal mutation also looks fine. Just out of curiosity, how did you locate those instances? By searching for calls to mutating functions or with an instrumented Emacs? ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 9:43 ` Mattias Engdegård @ 2020-05-17 16:38 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-17 16:38 UTC (permalink / raw) To: Mattias Engdegård; +Cc: Michael Heerdegen, 40671 On 5/17/20 2:43 AM, Mattias Engdegård wrote: > how did you locate those instances? By searching for calls to mutating functions or with an instrumented Emacs? I built an instrumented Emacs. I am working on making it faster, since I don't want the extra runtime checks to cost so much that people would prefer sticking with the current, sometimes-crashing Emacs. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 0:00 ` Michael Heerdegen 2020-05-11 0:26 ` Dmitry Gutov 2020-05-11 1:47 ` Drew Adams @ 2020-05-11 1:53 ` Paul Eggert 2020-05-11 3:18 ` Michael Heerdegen 2 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-11 1:53 UTC (permalink / raw) To: Michael Heerdegen Cc: Mattias Engdegård, Dmitry Gutov, 40671, Richard Stallman, ke.vigouroux [-- Attachment #1: Type: text/plain, Size: 3148 bytes --] On 5/10/20 5:00 PM, Michael Heerdegen wrote: > Are there any classes of "types" where all members are always mutable? Markers, for one. (This is mentioned in the previous paragraph.) There are others. We needn't list them all here. > Second point: you mix up objects vs. object evaluation. For conses you > speak about the objects, for symbols about the binding (i.e. the result > of the evaluation). Conses can also be evaluated (most programs are > conses), but that's surely not what you want to describe. I would not > say symbols are mutable. Symbols are constant AFAICT, their bindings > are not (variables are not constant). All good points. The simplest fix is to not mention symbol bindings here, as they're a complicated topic. Their mutability issues can be documented later, if someone wants to tackle the subject. > FWIW, I would feel better about the word "mutable" if you would > introduce the term like "safely mutable", and then say that we call it > just "mutable" in the following sections because this is shorter. Drew > mentioned his dislike for the term "safe" AFAIR but I think "my Emacs > won't crash if I follow this" vs. "it can crash" describes some kind of > safety. Ignore if this comment is irrelevant because this is already > done or treated otherwise. I think that's pretty much already done, since the definition of "mutable" says "it is safe to change their values". I'd rather not use the term "safely mutable" everywhere, as I don't want the manual to push the idea of "safely mutable" as opposed to "mutable"; instead, I want the manual to look forward to a future version where objects are either mutable or are immutable (and the latter is checked by the interpreter). >> + When the same value appears multiple times in a program, the Lisp >> +interpreter might save time or space by reusing existing values or >> +their components. For example, @code{(eq "abc" "abc")} returns > > I think we call "values" what evaluation of expressions yields, so > values don't appear in a program (to be read). They can if one feeds the values into 'eval', which runs part of a program. And 'read' can read programs. So I'm not sure I get the distinction. > Is it always the interpreter that > does this mapping? This section is written at a high level and uses "interpreter" to refer to the whole Emacs Lisp system. (This usage is longstanding in the manual.) So if any mapping is being done, it's by the "interpreter" in that sense. > "Same syntax" is not good as well: I don't see that phrase used in the manual. I assume you meant "same values"? > (eq (list 1 2 3) (list 1 2 3)) > > doesn't provoke the pitfall you warn about, but your wording doesn't > make clear why the one case is ok and the other is not. Maybe it's > again as simple as saying something about objects as being part of a > program? I changed it to use "parts of a program" and I can changed the "values" to "constants". Further patch attached; it also attempts to address the issues raised by Dmitry and Drew recently. I'm also attaching a single patch that accumulates it into all the patches proposed for emacs-27. [-- Attachment #2: 0001-doc-lispref-objects.texi-Mutability-More-tweaking.patch --] [-- Type: text/x-patch, Size: 2405 bytes --] From 3b200efd127a71c584dcb8942febc34021dffd22 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sun, 10 May 2020 18:44:46 -0700 Subject: [PATCH] * doc/lispref/objects.texi (Mutability): More tweaking. --- doc/lispref/objects.texi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 7727a630dd..136213ad66 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -2392,10 +2392,12 @@ Mutability Although numbers never change and all markers are mutable, some types have members some of which are mutable and others not. These -types include conses, vectors, strings, and symbols. For example, +types include conses, vectors, and strings. For example, although @code{"aaa"} yields a string that should not be changed, @code{(make-string 3 ?a)} yields a mutable string that can be -changed via later calls to @code{aset}. +changed via later calls to @code{aset}. Another example: +@code{(symbol-name 'cons)} yields a string @code{"cons"} that should +not be changed. A mutable object stops being mutable if it is part of an expression that is evaluated. For example: @@ -2413,9 +2415,7 @@ Mutability reverse does not occur: an object that should not be changed never becomes mutable afterwards. - Trying to modify a constant variable signals an error -(@pxref{Constant Variables}). -If a program attempts to change other objects that should not be + If a program attempts to change objects that should not be changed, the resulting behavior is undefined: the Lisp interpreter might signal an error, or it might crash or behave unpredictably in other ways.@footnote{This is the behavior specified for languages like @@ -2424,8 +2424,8 @@ Mutability error if a program attempts to change a constant. Ideally the Emacs Lisp interpreter will evolve in latter direction.} - When the same value appears multiple times in a program, the Lisp -interpreter might save time or space by reusing existing values or + When similar constants occur as parts of a program, the Lisp +interpreter might save time or space by reusing existing constants or their components. For example, @code{(eq "abc" "abc")} returns @code{t} if the interpreter creates only one instance of the string literal @code{"abc"}, and returns @code{nil} if it creates two -- 2.17.1 [-- Attachment #3: 0001-Don-t-use-constant-for-values-you-shouldn-t-change.patch --] [-- Type: text/x-patch, Size: 18478 bytes --] From 1a41838ba32429bb44c0d3ac933d266293f6cb3c Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sun, 10 May 2020 09:27:02 -0700 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20use=20=E2=80=9Cconstant?= =?UTF-8?q?=E2=80=9D=20for=20values=20you=20shouldn=E2=80=99t=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired by patch proposed by Dmitry Gutov (Bug#40671#393) and by further comments by him and by Michael Heerdegen in the same bug report. * doc/lispintro/emacs-lisp-intro.texi (setcar): Don’t push mutability here. * doc/lispref/eval.texi (Self-Evaluating Forms, Quoting) (Backquote): * doc/lispref/lists.texi (Modifying Lists): * doc/lispref/objects.texi (Lisp Data Types, Mutability): * doc/lispref/sequences.texi (Array Functions, Vectors): * doc/lispref/strings.texi (String Basics, Modifying Strings): Don’t use the word “constant” to describe all values that a program should not change. * doc/lispref/objects.texi (Mutability): Rename from “Constants and Mutability”. All uses changed. In a footnote, contrast the Emacs behavior with that of Common Lisp, Python, etc. for clarity, and say the goal is to be nicer. --- doc/lispintro/emacs-lisp-intro.texi | 5 +- doc/lispref/elisp.texi | 2 +- doc/lispref/eval.texi | 21 ++++--- doc/lispref/lists.texi | 16 ++--- doc/lispref/objects.texi | 98 +++++++++++++++-------------- doc/lispref/sequences.texi | 25 ++++---- doc/lispref/strings.texi | 11 ++-- 7 files changed, 87 insertions(+), 91 deletions(-) diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index ea16d9ef15..46462162ca 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7317,8 +7317,6 @@ setcar works is to experiment. We will start with the @code{setcar} function. @need 1200 -@cindex constant lists -@cindex mutable lists First, we can make a list and then set the value of a variable to the list, using the @code{setq} special form. Because we intend to use @code{setcar} to change the list, this @code{setq} should not use the @@ -7327,8 +7325,7 @@ setcar tried to change part of the program while running it. Generally speaking an Emacs Lisp program's components should be constant (or unchanged) while the program is running. So we instead construct an -animal list that is @dfn{mutable} (or changeable) by using the -@code{list} function, as follows: +animal list by using the @code{list} function, as follows: @smallexample (setq animals (list 'antelope 'giraffe 'lion 'tiger)) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index bba1b63115..9a6796790c 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -297,7 +297,7 @@ Top * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. Programming Types diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index baddce4d9c..39f342a798 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -158,11 +158,11 @@ Self-Evaluating Forms @end group @end example - A self-evaluating form yields constant conses, vectors and strings, and you -should not attempt to modify their contents via @code{setcar}, @code{aset} or + A self-evaluating form yields a value that becomes part of the program, +and you should not try to modify it via @code{setcar}, @code{aset} or similar operations. The Lisp interpreter might unify the constants yielded by your program's self-evaluating forms, so that these -constants might share structure. @xref{Constants and Mutability}. +constants might share structure. @xref{Mutability}. It is common to write numbers, characters, strings, and even vectors in Lisp code, taking advantage of the fact that they self-evaluate. @@ -564,8 +564,8 @@ Quoting @defspec quote object This special form returns @var{object}, without evaluating it. -The returned value is a constant, and should not be modified. -@xref{Constants and Mutability}. +The returned value might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @end defspec @cindex @samp{'} for quoting @@ -608,9 +608,9 @@ Quoting Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)} both yield lists equal to @code{(+ 1 2)}, the former yields a -freshly-minted mutable list whereas the latter yields a constant list -built from conses that may be shared with other constants. -@xref{Constants and Mutability}. +freshly-minted mutable list whereas the latter yields a list +built from conses that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. Other quoting constructs include @code{function} (@pxref{Anonymous Functions}), which causes an anonymous lambda expression written in Lisp @@ -710,8 +710,9 @@ Backquote @end example If a subexpression of a backquote construct has no substitutions or -splices, it acts like @code{quote} in that it yields constant conses, -vectors and strings that should not be modified. +splices, it acts like @code{quote} in that it yields conses, +vectors and strings that might be shared and should not be modified. +@xref{Self-Evaluating Forms}. @node Eval @section Eval diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index fcaf4386b1..ae793d5e15 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -873,8 +873,8 @@ Modifying Lists operations because they change existing list structure. Destructive operations should be applied only to mutable lists, that is, lists constructed via @code{cons}, @code{list} or similar -operations. Lists created by quoting are constants and should not be -changed by destructive operations. @xref{Constants and Mutability}. +operations. Lists created by quoting are part of the program and +should not be changed by destructive operations. @xref{Mutability}. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -911,7 +911,7 @@ Setcar @example @group -(setq x (list 1 2)) ; @r{Create a mutable list.} +(setq x (list 1 2)) @result{} (1 2) @end group @group @@ -931,7 +931,7 @@ Setcar @example @group -;; @r{Create two mutable lists that are partly shared.} +;; @r{Create two lists that are partly shared.} (setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @@ -1022,11 +1022,11 @@ Setcdr @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} +(setcdr x '(4)) @result{} (4) @end group @group @@ -1135,11 +1135,11 @@ Rearrangement @example @group -(setq x (list 1 2 3)) ; @r{Create a mutable list.} +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group -(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} +(nconc x '(4 5)) @result{} (1 2 3 4 5) @end group @group diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1d5b2c690f..136213ad66 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -46,10 +46,6 @@ Lisp Data Types Lisp variables can only take on values of a certain type. @xref{Variables with Restricted Values}.) - Some Lisp objects are @dfn{constant}: their values should never change. -Others are @dfn{mutable}: their values can be changed via destructive -operations that involve side effects. - This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how to use these types can be found in later chapters. @@ -63,7 +59,7 @@ Lisp Data Types * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. -* Constants and Mutability:: Whether an object's value can change. +* Mutability:: Some objects should not be modified. @end menu @node Printed Representation @@ -2379,51 +2375,59 @@ Equality Predicates @end example @end defun -@node Constants and Mutability -@section Constants and Mutability -@cindex constants +@node Mutability +@section Mutability @cindex mutable objects - Some Lisp objects are constant: their values should never change -during a single execution of Emacs running well-behaved Lisp code. -For example, you can create a new integer by calculating one, but you -cannot modify the value of an existing integer. - - Other Lisp objects are mutable: it is safe to change their values -via destructive operations involving side effects. For example, an -existing marker can be changed by moving the marker to point to -somewhere else. - - Although all numbers are constants and all markers are -mutable, some types contain both constant and mutable members. These -types include conses, vectors, strings, and symbols. For example, the string -literal @code{"aaa"} yields a constant string, whereas the function -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 part of an expression -that is evaluated. 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 -resulting behavior is undefined: the Lisp interpreter might or might -not detect the error, and if it does not detect the error the -interpreter can behave unpredictably thereafter. Another way to put -this is that although mutable objects are safe to change and constant -variables reliably prevent attempts to change them, other constants -are not safely mutable: if a misbehaving program tries to change such a -constant then the constant's value might actually change, or the -program might crash or worse. This problem occurs -with types that have both constant and mutable members, and that have -mutators like @code{setcar} and @code{aset} that are valid on mutable -objects but hazardous on constants. - - When the same constant occurs multiple times in a program, the Lisp + Some Lisp objects should never change. For example, the Lisp +expression @code{"aaa"} yields a string, but you should not change +its contents. Indeed, some objects cannot be changed; for example, +although you can create a new number by calculating one, Lisp provides +no operation to change the value of an existing number. + + Other Lisp objects are @dfn{mutable}: it is safe to change their +values via destructive operations involving side effects. For +example, an existing marker can be changed by moving the marker to +point to somewhere else. + + Although numbers never change and all markers are mutable, +some types have members some of which are mutable and others not. These +types include conses, vectors, and strings. For example, +although @code{"aaa"} yields a string that should not be changed, +@code{(make-string 3 ?a)} yields a mutable string that can be +changed via later calls to @code{aset}. Another example: +@code{(symbol-name 'cons)} yields a string @code{"cons"} that should +not be changed. + + A mutable object stops being mutable if it is part of an expression +that is evaluated. For example: + +@example +(let* ((x (list 0.5)) + (y (eval (list 'quote x)))) + (setcar x 1.5) ;; The program should not do this. + y) +@end example + +@noindent +Although the list @code{(0.5)} was mutable when it was created, it should not +have been changed via @code{setcar} because it given to @code{eval}. The +reverse does not occur: an object that should not be changed never +becomes mutable afterwards. + + If a program attempts to change objects that should not be +changed, the resulting behavior is undefined: the Lisp interpreter +might signal an error, or it might crash or behave unpredictably in +other ways.@footnote{This is the behavior specified for languages like +Common Lisp and C, and it differs from the behavior of languages like +JavaScript and Python where an interpreter is required to signal an +error if a program attempts to change a constant. Ideally the Emacs +Lisp interpreter will evolve in latter direction.} + + When similar constants occur as parts of a program, the Lisp interpreter might save time or space by reusing existing constants or -constant components. For example, @code{(eq "abc" "abc")} returns +their components. For example, @code{(eq "abc" "abc")} returns @code{t} if the interpreter creates only one instance of the string -constant @code{"abc"}, and returns @code{nil} if it creates two +literal @code{"abc"}, and returns @code{nil} if it creates two instances. Lisp programs should be written so that they work regardless of whether this optimization is in use. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1cb0d05cc7..91c3049f87 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ Sequence Functions @example @group -(setq bar (list 1 2)) ; @r{Create a mutable list.} +(setq bar (list 1 2)) @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} +(setq x (vector 'foo bar)) @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} +(setq x (list 'a 'b 'c)) @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ Sequence Functions For the vector, it is even simpler because you don't need setq: @example -(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} +(setq x (copy-sequence [1 2 3 4])) @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -331,6 +331,7 @@ Sequence Functions Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly encouraged to treat strings as immutable even when they are mutable. +@xref{Mutability}. @end defun @@ -374,7 +375,7 @@ Sequence Functions @example @group -(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} +(setq nums (list 1 3 2 6 5 4 0)) @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1229,7 @@ Array Functions @example @group -(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} +(setq w (vector 'foo 'bar 'baz)) @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1238,7 @@ Array Functions @end group @group -;; @r{@code{copy-sequence} creates a mutable string.} +;; @r{@code{copy-sequence} copies the string to be modified later.} (setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @@ -1247,9 +1248,7 @@ Array Functions @end group @end example -The @var{array} should be mutable; that is, it should not be a constant, -such as the constants created via quoting or via self-evaluating forms. -@xref{Constants and Mutability}. +The @var{array} should be mutable. @xref{Mutability}. If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a @@ -1262,7 +1261,6 @@ Array Functions @example @group -;; @r{Create a mutable vector and then fill it with zeros.} (setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @@ -1271,7 +1269,6 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -;; @r{Create a mutable string and then fill it with "-".} (setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @@ -1310,8 +1307,8 @@ Vectors evaluation: the result of evaluating it is the same vector. This does not evaluate or even examine the elements of the vector. @xref{Self-Evaluating Forms}. Vectors written with square brackets -are constants and should not be modified via @code{aset} or other -destructive operations. @xref{Constants and Mutability}. +should not be modified via @code{aset} or other destructive +operations. @xref{Mutability}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index a4c9c2549c..70c3b3cf4b 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -49,10 +49,9 @@ String Basics Since strings are arrays, and therefore sequences as well, you can operate on them with the general array and sequence functions documented -in @ref{Sequences Arrays Vectors}. For example, you can access or -change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, you should not -try to change the contents of constant strings (@pxref{Modifying Strings}). +in @ref{Sequences Arrays Vectors}. For example, you can access +individual characters in a string using the function @code{aref} +(@pxref{Array Functions}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -382,9 +381,7 @@ Modifying Strings @cindex string modification You can alter the contents of a mutable string via operations -described in this section. However, you should not try to use these -operations to alter the contents of a constant string. -@xref{Constants and Mutability}. +described in this section. @xref{Mutability}. The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 1:53 ` Paul Eggert @ 2020-05-11 3:18 ` Michael Heerdegen 0 siblings, 0 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-05-11 3:18 UTC (permalink / raw) To: Paul Eggert Cc: Mattias Engdegård, Dmitry Gutov, 40671, Richard Stallman, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > All good points. The simplest fix is to not mention symbol bindings > here, as they're a complicated topic. Yes, agreed. > >> + When the same value appears multiple times in a program, the Lisp > >> +interpreter might save time or space by reusing existing values or > >> +their components. For example, @code{(eq "abc" "abc")} returns > > > > I think we call "values" what evaluation of expressions yields, so > > values don't appear in a program (to be read). > > They can if one feeds the values into 'eval', which runs part of a > program. And 'read' can read programs. So I'm not sure I get the > distinction. Now I get how you meant this. I read the sentence more with a written program and syntax in mind. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-10 17:29 ` Paul Eggert 2020-05-11 0:00 ` Michael Heerdegen @ 2020-05-11 0:44 ` Dmitry Gutov 2020-05-11 1:57 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-11 0:44 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Richard Stallman On 10.05.2020 20:29, Paul Eggert wrote: > On 5/9/20 8:13 PM, Dmitry Gutov wrote: > >> You start talking about objects that "should [not] change". And give an example >> of an object that _cannot_ change. > > That's easily altered to also give an example of an object that should not > change; see attached patch. Quoting the new paragraph. Now it goes "should not" -> "cannot": + Some Lisp objects should never change. For example, the Lisp +expression @code{"aaa"} yields a string, but you should not change +its contents. Indeed, some objects cannot be changed; for example, +although you can create a new number by calculating one, Lisp provides +no operation to change the value of an existing number. "Indeed"? >> I could understand it if it was describing an existing type system of the >> language, or implementation internals, but this is a purely imaginary type >> system. > > objects.texi already talks about the Emacs Lisp type system and specifically > mentions strings, conses, etc. as types. Even if one considers the Emacs Lisp > type system to be "imaginary", it's reasonable to use the documentation's > already-existing terminology here. Strings, conses, etc, are anything but imaginary (try using one in a function that expects another, and you'll almost always get a runtime error). The changing "mutability" status is imaginary, however. This also requires the reader to read the manual without missing a reference. A regular person would not understand your meaning of "mutable" without following the reference to {Mutability}. Which not everybody is going to do, and which is harder to do when reading a printed version. >> the list object didn't change, just an outside reference to its head was >> created, > > The attached patch alters the example so that the list object does change (or at > least tries to). Does is ignore the possibility of the example in the previous version, then? >> The opposite of "mutable" is "immutable". Are string literals immutable? They are >> not. > > They might be mutable, and they might not be. The documentation deliberately > doesn't say, because we don't want to document the details (they have changed in > the past and are likely to change in the future). I'm trying to point out the incompatibility with the regular meanings of the words used. Also see Michael's suggestion. >> Overall the phrase "that might be shared" is a good replacement. Why not keep to >> it? > > Because it's not an accurate statement of the problem. The set of objects that > might be shared differs from the set of objects that should not change. The > Mutability node focuses on the latter set of objects, and gives the former as an > example but it is not the only sort of object that should not change. But if we don't mention such cases in "Mutability", where do we cover them? I'm also looking at the new example: +(let* ((x (list 0.5)) + (y (eval (list 'quote x)))) + (setcar x 1.5) ;; The program should not do this. + y) Why is this a problem? Do we expect this it could lead to a segfault? Evaluating this expression in IELM leads to a stable result. Putting it in a function doesn't bring any surprises either. Example: ELISP> (defun test (v) (let* ((x (list v)) (y (eval (list 'quote x)))) (setcar x 1.5) y)) test ELISP> (test 3) (1.5) It's an advanced, yes, but clearly the expected behavior if someone wrote a function like that. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 0:44 ` Dmitry Gutov @ 2020-05-11 1:57 ` Paul Eggert 2020-05-12 1:59 ` Dmitry Gutov 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-05-11 1:57 UTC (permalink / raw) To: Dmitry Gutov Cc: ke.vigouroux, 40671, Michael Heerdegen, Mattias Engdegård, Richard Stallman On 5/10/20 5:44 PM, Dmitry Gutov wrote: > "Indeed"? Indeed yes. :-) > The changing "mutability" status is imaginary, however. It's part of a spec. Not every constraint in a spec needs to be enforced directly by the implementation. That doesn't mean these constraints are "imaginary". > This also requires the reader to read the manual without missing a reference. A > regular person would not understand your meaning of "mutable" without following > the reference to {Mutability}. If a paragraph says "mutable" and has a cross-reference to the "Mutability" section, that's good enough. This is a reference manual, not a tutorial, and we can assume a reasonable level of competence on the part of the reader. > Does is ignore the possibility of the example in the previous version, then? I don't understand this remark. > I'm trying to point out the incompatibility with the regular meanings of the > words used. >> Because it's not an accurate statement of the problem. The set of objects that >> might be shared differs from the set of objects that should not change. The >> Mutability node focuses on the latter set of objects, and gives the former as an >> example but it is not the only sort of object that should not change. > > But if we don't mention such cases in "Mutability", where do we cover them? Fair enough. I added an example of such a case to "Mutability" in the proposal in my most-recent email (Bug#40671#441). > +(let* ((x (list 0.5)) > + (y (eval (list 'quote x)))) > + (setcar x 1.5) ;; The program should not do this. > + y) > > Why is this a problem? Do we expect this it could lead to a segfault? Probably not a segfault in the current implementation, but the behavior isn't defined. And we don't want the behavior to be defined, as that would prohibit some optimizations that may be coming down the road. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-11 1:57 ` Paul Eggert @ 2020-05-12 1:59 ` Dmitry Gutov 2020-05-17 1:28 ` Paul Eggert 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-12 1:59 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, ke.vigouroux, 40671, Mattias Engdegård, Richard Stallman On 11.05.2020 04:57, Paul Eggert wrote: > On 5/10/20 5:44 PM, Dmitry Gutov wrote: > >> "Indeed"? > > Indeed yes. :-) That paragraph doesn't scan. You could replace that word with "And", though. >> The changing "mutability" status is imaginary, however. > > It's part of a spec. Not every constraint in a spec needs to be enforced > directly by the implementation. That doesn't mean these constraints are "imaginary". Part of the "spec" you just added in this series of patches. I think that's exactly what a "constraint" means: something that is enforced. >>> Because it's not an accurate statement of the problem. The set of objects that >>> might be shared differs from the set of objects that should not change. The >>> Mutability node focuses on the latter set of objects, and gives the former as an >>> example but it is not the only sort of object that should not change. >> >> But if we don't mention such cases in "Mutability", where do we cover them? > > Fair enough. I added an example of such a case to "Mutability" in the proposal > in my most-recent email (Bug#40671#441). Curious case of an meaningful reference where I have to construct the URL manually anyway. The symbol-name example? I'm not sure it's really important to warn about this one in particular. But are we effectively saying "there exist values that are unsafe to modify, for example, any return values of symbol-name", and that's it? When one tries to describe "unsafe" things to do, they don't just give a few examples, they usually try to cover all cases. Perhaps by including some false positives (which the 'let*' example below, I think, is), but trying hard to avoid false negatives. Inventing a name for such values doesn't help if the user doesn't have enough knowledge to avoid all members of this set. Or is "part of an expression that is evaluated" after all the test we'll be teaching? By the way, I have read last two paragraphs of that section now. C and "constants" are still there. >> +(let* ((x (list 0.5)) >> + (y (eval (list 'quote x)))) >> + (setcar x 1.5) ;; The program should not do this. >> + y) >> >> Why is this a problem? Do we expect this it could lead to a segfault? > > Probably not a segfault in the current implementation, but the behavior isn't > defined. And we don't want the behavior to be defined, as that would prohibit > some optimizations that may be coming down the road. I'm curious to see the discussion about actually making this error at runtime in one of the next Emacs version. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-12 1:59 ` Dmitry Gutov @ 2020-05-17 1:28 ` Paul Eggert 2020-05-17 5:02 ` Michael Heerdegen 2020-05-17 12:39 ` Dmitry Gutov 0 siblings, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-17 1:28 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, ke.vigouroux, 40671, Mattias Engdegård, Richard Stallman [-- Attachment #1: Type: text/plain, Size: 2599 bytes --] On 5/11/20 6:59 PM, Dmitry Gutov wrote: > I think that's exactly what a "constraint" means: something that is enforced. Not necessarily. In some software systems constraints are not enforced. (Use Google to search for "unenforced constraints", which can be quite the thing in the database world.) But I am straying from the documentation issue. > The symbol-name example? I'm not sure it's really important to > warn about this one in particular. OK, but then you also write: > When one tries to > describe "unsafe" things to do, they don't just give a few examples, they > usually try to cover all cases. ... and symbol-name is one of the cases. As far as the bigger project (cover all the cases) goes, I don't know how feasible that would be. I suppose someone could take that on as a further task. In the attached patch I did add one more example, of calling the copy-sequence function, but there would be lots more examples where that came from. > Inventing a name for such values doesn't help if the user doesn't have enough > knowledge to avoid all members of this set. Or is "part of an expression that is > evaluated" after all the test we'll be teaching? No, it's not the only way that something can be a constant. This is why the (symbol-name 'cons) example is relevant: it yields a string that has never been "part of an expression that is evaluated". > By the way, I have read last two paragraphs of that section now. C and > "constants" are still there. It's appropriate to talk about constants in the footnote that mentions languages that have constants. And the footnote is helpful, because it documents the core issue that prompted this long thread: different languages/traditions mean different things by the word "constant" and/or "immutable", and the footnote makes it clear that the documentation's "objects that should not be changed" follows the Common Lisp / C tradition, not the Python / JavaScript tradition. That being said, it'd be helpful if the footnote mentions both "constants" and "immutable objects" if only to remind readers of relevant buzzwords. So I did that in the attached patch. > I'm curious to see the discussion about actually making this error at runtime in > one of the next Emacs version. Me too. That's for a later thread, one that I'd like to get rolling instead of worrying about the minor details in the current doc. To help get things rolling I installed the patch that I proposed earlier, followed by the attached minor patch that attempt to address the abovementioned issues. I plan to look at improving the runtime checking next. [-- Attachment #2: 0001-Minor-fixups-for-mutability-doc.patch --] [-- Type: text/x-patch, Size: 2686 bytes --] From b48ab743a861b8041518ce7459bde51c3dd02ee0 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sat, 16 May 2020 18:16:23 -0700 Subject: [PATCH] Minor fixups for mutability doc * doc/lispref/objects.texi (Mutability): Minor fixups in response to a comment by Dmitry Gutov (Bug#40671#477). --- doc/lispref/objects.texi | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 136213ad66..5c5f89eb43 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -2381,7 +2381,7 @@ that for two strings to be equal, they have the same text properties. Some Lisp objects should never change. For example, the Lisp expression @code{"aaa"} yields a string, but you should not change -its contents. Indeed, some objects cannot be changed; for example, +its contents. And some objects cannot be changed; for example, although you can create a new number by calculating one, Lisp provides no operation to change the value of an existing number. @@ -2393,11 +2393,10 @@ point to somewhere else. Although numbers never change and all markers are mutable, some types have members some of which are mutable and others not. These types include conses, vectors, and strings. For example, -although @code{"aaa"} yields a string that should not be changed, -@code{(make-string 3 ?a)} yields a mutable string that can be -changed via later calls to @code{aset}. Another example: -@code{(symbol-name 'cons)} yields a string @code{"cons"} that should -not be changed. +although @code{"cons"} and @code{(symbol-name 'cons)} both yield +strings that should not be changed, @code{(copy-sequence "cons")} and +@code{(make-string 3 ?a)} both yield mutable strings that can be +changed via later calls to @code{aset}. A mutable object stops being mutable if it is part of an expression that is evaluated. For example: @@ -2419,9 +2418,9 @@ becomes mutable afterwards. changed, the resulting behavior is undefined: the Lisp interpreter might signal an error, or it might crash or behave unpredictably in other ways.@footnote{This is the behavior specified for languages like -Common Lisp and C, and it differs from the behavior of languages like +Common Lisp and C for constants, and this differs from languages like JavaScript and Python where an interpreter is required to signal an -error if a program attempts to change a constant. Ideally the Emacs +error if a program attempts to change an immutable object. Ideally the Emacs Lisp interpreter will evolve in latter direction.} When similar constants occur as parts of a program, the Lisp -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 1:28 ` Paul Eggert @ 2020-05-17 5:02 ` Michael Heerdegen 2020-05-17 16:34 ` Paul Eggert 2020-05-17 12:39 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-05-17 5:02 UTC (permalink / raw) To: Paul Eggert Cc: Mattias Engdegård, Dmitry Gutov, 40671, Richard Stallman, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > ... and symbol-name is one of the cases. I'm wondering about this one for a while, too. Is it that the resulting string is really like the "object is part of an evaluated program" cases, or is it just that modifying it has an unwanted side effect (changing the name of the symbol, and Emacs doesn't handle this correctly). I mean, you can modify a lot of objects in Emacs and that will cause trouble. We surely don't want to call them all constant or not safely mutable or whatever. How is the result of `symbol-name' different from these other cases? Is it only that the side effect/ mess is not visible from Lisp? Where do you draw the line? Yes, the hidden question is still what your definition of safely mutable is. Thanks, Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 5:02 ` Michael Heerdegen @ 2020-05-17 16:34 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-17 16:34 UTC (permalink / raw) To: Michael Heerdegen Cc: Mattias Engdegård, Dmitry Gutov, 40671, Richard Stallman, ke.vigouroux On 5/16/20 10:02 PM, Michael Heerdegen wrote: > you can modify a lot of objects in Emacs and that > will cause trouble. We surely don't want to call them all constant or > not safely mutable or whatever. We may not *want* to do that, but that's what we're doing now (with the two classes currently documented as "mutable objects" and "objects that you should not change"). And I don't see any easy way to change the documentation to draw the line that we'd like to draw (namely, between "mutable objects" and "objects that you cannot change") because that's not how Emacs works and changing Emacs's behavior will be nontrivial. At this point I suspect it'll be a better of our time to look into improving Emacs's behavior in this area, and worry about documentation wording later. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 1:28 ` Paul Eggert 2020-05-17 5:02 ` Michael Heerdegen @ 2020-05-17 12:39 ` Dmitry Gutov 2020-05-17 16:21 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-17 12:39 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, ke.vigouroux, 40671, Mattias Engdegård, Richard Stallman On 17.05.2020 04:28, Paul Eggert wrote: > On 5/11/20 6:59 PM, Dmitry Gutov wrote: > >> I think that's exactly what a "constraint" means: something that is enforced. > > Not necessarily. In some software systems constraints are not enforced. (Use > Google to search for "unenforced constraints", which can be quite the thing in > the database world.) But I am straying from the documentation issue. An existence of a technical term doesn't really cancel out the regular meaning of the word. >> The symbol-name example? I'm not sure it's really important to >> warn about this one in particular. > > OK, but then you also write: > >> When one tries to >> describe "unsafe" things to do, they don't just give a few examples, they >> usually try to cover all cases. > > ... and symbol-name is one of the cases. These are just two distinct points: 1. You seem to be trying to redefine the term "motable" as a way to avoid enumerating all possible cases. But since the meaning of the term is different from how it is understood in the English language, it should at least have a proper definition. But the said definition would have to cover the possible cases too. 2. symbol-name seems like something we don't have to explain specially. So if that's the only counter-example to "values that appear in expressions", or whichever phrase we chose, then we could as well just on the phrase and dispense with additional complications. Which would also make having a redefinition of the term "mutable" less relevant. > As far as the bigger project (cover all the cases) goes, I don't know how > feasible that would be. I suppose someone could take that on as a further task. > In the attached patch I did add one more example, of calling the copy-sequence > function, but there would be lots more examples where that came from. > >> Inventing a name for such values doesn't help if the user doesn't have enough >> knowledge to avoid all members of this set. Or is "part of an expression that is >> evaluated" after all the test we'll be teaching? > > No, it's not the only way that something can be a constant. This is why the > (symbol-name 'cons) example is relevant: it yields a string that has never been > "part of an expression that is evaluated". There's an argument to be made that the name of the symbol 'cons is part of any expression or program that uses `cons'. >> By the way, I have read last two paragraphs of that section now. C and >> "constants" are still there. > > It's appropriate to talk about constants in the footnote that mentions languages > that have constants. And the footnote is helpful, because it documents the core > issue that prompted this long thread: different languages/traditions mean > different things by the word "constant" and/or "immutable", and the footnote > makes it clear that the documentation's "objects that should not be changed" > follows the Common Lisp / C tradition, not the Python / JavaScript tradition. > > That being said, it'd be helpful if the footnote mentions both "constants" and > "immutable objects" if only to remind readers of relevant buzzwords. So I did > that in the attached patch. I like that change, thank you. >> I'm curious to see the discussion about actually making this error at runtime in >> one of the next Emacs version. > > Me too. That's for a later thread, one that I'd like to get rolling instead of > worrying about the minor details in the current doc. To help get things rolling > I installed the patch that I proposed earlier, followed by the attached minor > patch that attempt to address the abovementioned issues. I plan to look at > improving the runtime checking next. OK, thank you. My intuition, though, that making cases like the one you just changed in emacs-lisp-mode-tests.el blow up at runtime will create a massive backward incompatibility. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-17 12:39 ` Dmitry Gutov @ 2020-05-17 16:21 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-17 16:21 UTC (permalink / raw) To: Dmitry Gutov Cc: Michael Heerdegen, ke.vigouroux, 40671, Mattias Engdegård, Richard Stallman On 5/17/20 5:39 AM, Dmitry Gutov wrote: > An existence of a technical term doesn't really cancel out the regular meaning > of the word. I continue to be skeptical that "constraints are always enforced" is the regular meaning of the word "constraints" in computing. Lots of constraints are not enforced in the computing world. Internet RFCs are a classic example: "Be liberal in what you accept" means "Don't enforce constraints". But again, we are straying from the point at hand, as the word "constraints" isn't used in the documentation when talking about mutability. > 1. You seem to be trying to redefine the term "motable" as a way to avoid > enumerating all possible cases. That is a normal practice for definitions, and this practice increases the utility of the documentation. The Emacs manual defines "string" without enumering all possible cases of strings (whether they come from the program text, or from reading input, or from symbol-name, etc.) because enumerating all cases would be bloat that would cause more harm than good. Similarly, the manual defines "mutable" without defining all possible cases of mutable objects. > 2. symbol-name seems like something we don't have to explain specially. I don't understand this comment. symbol-name is just an example. It's helpful to have an example or two, even if they're not absolutely required. > There's an argument to be made that the name of the symbol 'cons is part of any > expression or program that uses `cons'. Sure, and that argument is part of any bigger project to document more about mutability ("covering all the cases" in some way). This would not be a trivial project, and it's not something we have to do today. > My intuition, though, that making cases like the one you just changed in emacs-lisp-mode-tests.el blow up at runtime will create a massive backward incompatibility. I'm sure there are compatibility issues. But we already have those issues: an Elisp program that modifies a string constant is already "broken" in that it's making assumptions that have never been documented and are sometimes not true even now. Emacs used to have some runtime checking for this bug but it doesn't now, and when we reinstitute checking we will undoubtedly shake out some latent bugs in user code. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 6:09 ` Paul Eggert 2020-05-05 12:38 ` Dmitry Gutov @ 2020-05-05 17:40 ` Drew Adams 2020-05-05 18:49 ` Dmitry Gutov 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-05-05 17:40 UTC (permalink / raw) To: Paul Eggert, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman Apologies for chiming in here again. And I haven't read the proposed text or followed the thread recently. But I just saw "Dangerous Mutations". I really don't think that it's helpful or appropriate to speak of danger in the context of the gotcha we've been discussing. Danger is danger. Yes, with undefined behavior, and with possible modification of list structure etc., there is the possibility of loss of data, and that's not a good thing. Undefined is scary. But I'm not in favor of crying "DANGER" about such things. At all. Check the Common Lisp doc. You don't find such screaming warnings plastered throughout, whenever it comes to destructive modification. The word "destructive" is sufficiently strong. And in the case of the gotchas being discussed it's not necessarily even destructive modification. The unknown/undefined is just that. No need (and inappropriate) to wrap it DANGEROUS! Just one opinion. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 17:40 ` Drew Adams @ 2020-05-05 18:49 ` Dmitry Gutov 2020-05-05 19:26 ` Drew Adams 0 siblings, 1 reply; 170+ messages in thread From: Dmitry Gutov @ 2020-05-05 18:49 UTC (permalink / raw) To: Drew Adams, Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 05.05.2020 20:40, Drew Adams wrote: > The word "destructive" is sufficiently strong. > And in the case of the gotchas being discussed > it's not necessarily even destructive > modification. It's not modification if it's not destructive. At least, in the context of the problem we're trying to describe. Destructive modification, by itself, is a very regular occasion. Not something to warn against. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 18:49 ` Dmitry Gutov @ 2020-05-05 19:26 ` Drew Adams 0 siblings, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-05-05 19:26 UTC (permalink / raw) To: Dmitry Gutov, Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > It's not modification if it's not destructive. At least, in the context > of the problem we're trying to describe. > > Destructive modification, by itself, is a very regular occasion. Not > something to warn against. Whatever. My point is that there's no need to scream "Danger!". A warning does not imply danger. And a tip about a gotcha is not necessarily even a warning. Can the consequences ever be awful? Presumably. Will they often be awful? Not likely. The most likely negative effect is spending time trying to figure out what's happening. That's why we should have a tip about the gotcha. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-04 17:52 ` Paul Eggert 2020-05-05 1:39 ` Dmitry Gutov @ 2020-05-05 20:48 ` Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 2020-05-09 5:57 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-05-05 20:48 UTC (permalink / raw) To: Paul Eggert Cc: Richard Stallman, Michael Heerdegen, Mattias Engdegård, Dmitry Gutov, Drew Adams, 40671 Paul Eggert <eggert@cs.ucla.edu> writes: > On 5/4/20 3:16 AM, Dmitry Gutov wrote: >> On 04.05.2020 02:10, Paul Eggert wrote: >>> The term you used was "Objects referenced from executable code". But that term >>> includes pretty much every object used in Elisp, at least until the object >>> becomes unreachable and is garbage-collected. >> >> I see. Could you present a specific counter-example, however? >> >> One where the phrasing "referenced from executable code" would apply, but "part >> of expressions that are evaluated" wouldn't. > > Pretty much any ordinary cons will do. In (let ((x (cons 0 0))) (setcar x 1)), > for example, the cons is referenced from executable code but it's OK to modify > the cons. The cons becomes unreachable when the 'let' finishes. The cons is not > part of any expression that is evaluated. > > The problem here evidently is one of terminology, not of understanding the > underlying issues. When I read "Objects referenced from executable code" I > evidently got a different meaning than what you intended. These things happen > when introducing a new terminology. Would the expression "constant form" be appropriate? Here is the definition given in the CLHS (in the glossary). Constant form: Any form for which evaluation always yields the same value, that neither affects nor is affected by the environment in which it is evaluated (except that is permitted to refer to the names of constant variables defined in the environment), and that neither affects nor is affected by the state of any object except those objects that are otherwise inaccessible parts of objects created by the form itself. For instance, a car form in which the argument is a quote form is a constant form. If I understand correctly, the problem is partially related to self-modifying code. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-05-05 20:48 ` Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2020-05-09 5:57 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-05-09 5:57 UTC (permalink / raw) To: Kevin Vigouroux Cc: 40671, Michael Heerdegen, Mattias Engdegård, Dmitry Gutov, Richard Stallman On 5/5/20 1:48 PM, Kevin Vigouroux wrote: > Would the expression "constant form" be appropriate? Not exactly, as that refers to a form in the source code, whereas we are talking about objects available at run-time. There is overlap between the two concepts but some objects are "constant" (in the sense of the current emacs-27 doc) without appearing in the source code. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 20:09 ` Paul Eggert 2020-04-28 21:10 ` Dmitry Gutov @ 2020-04-28 21:18 ` Dmitry Gutov 1 sibling, 0 replies; 170+ messages in thread From: Dmitry Gutov @ 2020-04-28 21:18 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 28.04.2020 23:09, Paul Eggert wrote: > I thought you were saying that we should distinguish among the types of > constants Among the types of mutable values. Between the "normal" and "do not touch" ones. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 8:17 ` Paul Eggert 2020-04-28 13:54 ` Dmitry Gutov @ 2020-04-28 17:25 ` Drew Adams 2020-04-28 17:47 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Drew Adams @ 2020-04-28 17:25 UTC (permalink / raw) To: Paul Eggert, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman > There's certainly no intent to side-step. > And I don't sense that there's really > much disagreement here: we both agree that > the current behavior is unfortunate, > the major point of disagreement is about > terminology in the documentation. Has anyone agreed with you here about your use of "cannot" instead of "should not" and your unconventional use of "constant"/"immutable" and "mutable"? I don't think I've seen any support for that here (did I just miss it?). Still you persist. I don't really see the doc/message for users getting clearer; it seems like the waters are being muddied. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 17:25 ` Drew Adams @ 2020-04-28 17:47 ` Paul Eggert 2020-04-29 0:32 ` Michael Heerdegen 0 siblings, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-28 17:47 UTC (permalink / raw) To: Drew Adams, Dmitry Gutov Cc: Michael Heerdegen, Mattias Engdegård, ke.vigouroux, 40671, Richard Stallman On 4/28/20 10:25 AM, Drew Adams wrote: > Has anyone agreed with you Nobody's happy with the current documentation's language (not even me), but nobody has proposed specific wording improvements either. That's what committees do sometimes; we might not agree, but the guy who does most of the work generates something that nobody has the time to improve significantly. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-28 17:47 ` Paul Eggert @ 2020-04-29 0:32 ` Michael Heerdegen 2020-04-29 1:40 ` Paul Eggert 2020-04-29 16:36 ` Paul Eggert 0 siblings, 2 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-04-29 0:32 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Paul Eggert <eggert@cs.ucla.edu> writes: > On 4/28/20 10:25 AM, Drew Adams wrote: > > Has anyone agreed with you > > Nobody's happy with the current documentation's language (not even > me), but nobody has proposed specific wording improvements either. I think the feedback would be better if you had been more cooperative/ open minded at the beginning. You have started committing stuff without even asking whether people like your approach in general. What if people think slight rewording is not enough? You started the thing not very cooperatively, and that's how things developed. Just my point of view. > That's what committees do sometimes; we might not agree, but the guy > who does most of the work generates something that nobody has the time > to improve significantly. We all do stuff here nobody else has time to do. Obviously, in this case a collective brainstorming at the beginning would have been better. Apart from questions like "please give me a better wording for this I wrote if _you_ don't like it", why did you never ask "how could we improve this aspect of the manual, what do you think?" or "do people agree with what I have in mind?". Now stuff is already in the repo, it's inconvenient to review, and the committer doesn't seem to be very open to other perspectives. A lot of the discussion here currently is rather destructive, yes, that's not good, I guess everyone involved is to blame. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 0:32 ` Michael Heerdegen @ 2020-04-29 1:40 ` Paul Eggert 2020-04-29 4:40 ` Michael Heerdegen 2020-04-29 16:36 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-29 1:40 UTC (permalink / raw) To: Michael Heerdegen Cc: ke.vigouroux, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman On 4/28/20 5:32 PM, Michael Heerdegen wrote: > A lot of the discussion here currently is rather destructive, yes, > that's not good, I guess everyone involved is to blame. At this point the disagreement over a relatively minor terminology issue is so lengthy that the whole documentation change is arguably more trouble than it's worth. So again: anyone who wants to revert my recent doc changes to emacs-27 is welcome to do so. Or, if you'd prefer to uniformly subsitute "literal object" for "constant", please feel free to do that too. It's really not worth arguing about, and I apologize for stirring up this hornet's nest. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 1:40 ` Paul Eggert @ 2020-04-29 4:40 ` Michael Heerdegen 2020-04-29 8:01 ` Eli Zaretskii 0 siblings, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-04-29 4:40 UTC (permalink / raw) To: Paul Eggert Cc: ke.vigouroux, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman Paul Eggert <eggert@cs.ucla.edu> writes: > So again: anyone who wants to revert my recent doc changes to emacs-27 > is welcome to do so. Or, if you'd prefer to uniformly subsitute > "literal object" for "constant" I don't think "literal" covers all the cases you have in mind. I don't have an idea for a name of the class of cases you have in mind, because I would not subsume all examples you gave in one class at all. They might be implementation- or memory-wise, but I don't think this is a good perspective to describe a high-level language. For example, the result of `symbol-name'. In my eyes, modifying the result has a side effect (renaming the symbol, but in a way that is not supported), and this side effect will have undesired consequences. But that is true for other strings, too, that you would call mutable. It's hard to draw a clear line here, unless you think (C-) implementation wise. For what you describe I would just say that under certain conditions certain objects that are, in principle, mutable, should not be changed in certain circumstances because of implementation details, here is a list of such cases: ..., that's it. I'm sorry that I also can't offer patches because I don't speak texinfo. > It's really not worth arguing about, and I apologize for stirring up > this hornet's nest. I've never been called a hornet before. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 4:40 ` Michael Heerdegen @ 2020-04-29 8:01 ` Eli Zaretskii 0 siblings, 0 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-04-29 8:01 UTC (permalink / raw) To: Michael Heerdegen; +Cc: ke.vigouroux, eggert, 40671, mattiase, dgutov, rms > From: Michael Heerdegen <michael_heerdegen@web.de> > Date: Wed, 29 Apr 2020 06:40:39 +0200 > Cc: ke.vigouroux@laposte.net, 40671@debbugs.gnu.org, > Mattias Engdegård <mattiase@acm.org>, > Dmitry Gutov <dgutov@yandex.ru>, Richard Stallman <rms@gnu.org> > > I'm sorry that I also can't offer patches because I don't speak texinfo. Would you be willing to review the relevant portions of the manual and post comments to the parts that in your opinion need further work? I think that would be a good step towards making the text less controversial. TIA ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-29 0:32 ` Michael Heerdegen 2020-04-29 1:40 ` Paul Eggert @ 2020-04-29 16:36 ` Paul Eggert 1 sibling, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-29 16:36 UTC (permalink / raw) To: Michael Heerdegen Cc: ke.vigouroux, 40671, Mattias Engdegård, Dmitry Gutov, Richard Stallman [-- Attachment #1: Type: text/plain, Size: 496 bytes --] On 4/28/20 5:32 PM, Michael Heerdegen wrote: > Now stuff is already in the repo, it's inconvenient to review, I took the trouble of retrieving all changes to the emacs-27 documentation since this exercise started, discarding the irrelevant changes, with the result being the attached diff. This should make the new material more convenient to review. Of course this is not a complete substitute for reviewing what's in the manual now, as I could have well missed some stuff that needs changing. [-- Attachment #2: constants.diff --] [-- Type: text/x-patch, Size: 20883 bytes --] diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index 66aa97e20a..ea16d9ef15 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7317,11 +7317,21 @@ setcar works is to experiment. We will start with the @code{setcar} function. @need 1200 +@cindex constant lists +@cindex mutable lists First, we can make a list and then set the value of a variable to the -list, using the @code{setq} function. Here is a list of animals: +list, using the @code{setq} special form. Because we intend to use +@code{setcar} to change the list, this @code{setq} should not use the +quoted form @code{'(antelope giraffe lion tiger)}, as that would yield +a list that is part of the program and bad things could happen if we +tried to change part of the program while running it. Generally +speaking an Emacs Lisp program's components should be constant (or +unchanged) while the program is running. So we instead construct an +animal list that is @dfn{mutable} (or changeable) by using the +@code{list} function, as follows: @smallexample -(setq animals '(antelope giraffe lion tiger)) +(setq animals (list 'antelope 'giraffe 'lion 'tiger)) @end smallexample @noindent @@ -7398,7 +7408,7 @@ setcdr domesticated animals by evaluating the following expression: @smallexample -(setq domesticated-animals '(horse cow sheep goat)) +(setq domesticated-animals (list 'horse 'cow 'sheep 'goat)) @end smallexample @need 1200 @@ -8846,7 +8856,7 @@ kill-new function @smallexample @group -(setq trees '(maple oak pine birch)) +(setq trees (list 'maple 'oak 'pine 'birch)) @result{} (maple oak pine birch) @end group @@ -9366,7 +9376,7 @@ cons & search-fwd Review @smallexample @group -(setq triple '(1 2 3)) +(setq triple (list 1 2 3)) (setcar triple '37) diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi index 8be8307c75..ec76e83db1 100644 --- a/doc/lispref/edebug.texi +++ b/doc/lispref/edebug.texi @@ -858,7 +858,7 @@ Printing in Edebug Here is an example of code that creates a circular structure: @example -(setq a '(x y)) +(setq a (list 'x 'y)) (setcar a a) @end example diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index cfd96f7aa6..bba1b63115 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -297,6 +297,7 @@ Top * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. +* Constants and Mutability:: Whether an object's value can change. Programming Types diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi index cd45c8df03..baddce4d9c 100644 --- a/doc/lispref/eval.texi +++ b/doc/lispref/eval.texi @@ -158,6 +158,12 @@ Self-Evaluating Forms @end group @end example + A self-evaluating form yields constant conses, vectors and strings, and you +should not attempt to modify their contents via @code{setcar}, @code{aset} or +similar operations. The Lisp interpreter might unify the constants +yielded by your program's self-evaluating forms, so that these +constants might share structure. @xref{Constants and Mutability}. + It is common to write numbers, characters, strings, and even vectors in Lisp code, taking advantage of the fact that they self-evaluate. However, it is quite unusual to do this for types that lack a read @@ -558,6 +564,8 @@ Quoting @defspec quote object This special form returns @var{object}, without evaluating it. +The returned value is a constant, and should not be modified. +@xref{Constants and Mutability}. @end defspec @cindex @samp{'} for quoting @@ -598,6 +606,12 @@ Quoting @end group @end example + Although the expressions @code{(list '+ 1 2)} and @code{'(+ 1 2)} +both yield lists equal to @code{(+ 1 2)}, the former yields a +freshly-minted mutable list whereas the latter yields a constant list +built from conses that may be shared with other constants. +@xref{Constants and Mutability}. + Other quoting constructs include @code{function} (@pxref{Anonymous Functions}), which causes an anonymous lambda expression written in Lisp to be compiled, and @samp{`} (@pxref{Backquote}), which is used to quote @@ -695,6 +709,9 @@ Backquote @end group @end example +If a subexpression of a backquote construct has no substitutions or +splices, it acts like @code{quote} in that it yields constant conses, +vectors and strings that should not be modified. @node Eval @section Eval diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi index fd269d520c..1e81fb1dc5 100644 --- a/doc/lispref/keymaps.texi +++ b/doc/lispref/keymaps.texi @@ -1441,10 +1441,10 @@ Changing Key Bindings @smallexample @group -(setq map '(keymap - (?1 . olddef-1) - (?2 . olddef-2) - (?3 . olddef-1))) +(setq map (list 'keymap + (cons ?1 olddef-1) + (cons ?2 olddef-2) + (cons ?3 olddef-1))) @result{} (keymap (49 . olddef-1) (50 . olddef-2) (51 . olddef-1)) @end group diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index 27fa5385e3..ea44e01f48 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -866,10 +866,15 @@ List Variables @node Modifying Lists @section Modifying Existing List Structure @cindex destructive list operations +@cindex mutable lists You can modify the @sc{car} and @sc{cdr} contents of a cons cell with the primitives @code{setcar} and @code{setcdr}. These are destructive operations because they change existing list structure. +Destructive operations should be applied only to mutable lists, +that is, lists constructed via @code{cons}, @code{list} or similar +operations. Lists created by quoting are constants and should not be +changed by destructive operations. @xref{Constants and Mutability}. @cindex CL note---@code{rplaca} vs @code{setcar} @quotation @@ -906,7 +911,7 @@ Setcar @example @group -(setq x '(1 2)) +(setq x (list 1 2)) ; @r{Create a mutable list.} @result{} (1 2) @end group @group @@ -926,8 +931,8 @@ Setcar @example @group -;; @r{Create two lists that are partly shared.} -(setq x1 '(a b c)) +;; @r{Create two mutable lists that are partly shared.} +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @result{} (z b c) @@ -1017,11 +1022,11 @@ Setcdr @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) ; @r{Create a mutable list.} @result{} (1 2 3) @end group @group -(setcdr x '(4)) +(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} @result{} (4) @end group @group @@ -1037,7 +1042,7 @@ Setcdr @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cdr (cdr x1))) @result{} (c) @@ -1069,7 +1074,7 @@ Setcdr @example @group -(setq x1 '(a b c)) +(setq x1 (list 'a 'b 'c)) @result{} (a b c) (setcdr x1 (cons 'd (cdr x1))) @result{} (d b c) @@ -1130,11 +1135,11 @@ Rearrangement @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) ; @r{Create a mutable list.} @result{} (1 2 3) @end group @group -(nconc x '(4 5)) +(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} @result{} (1 2 3 4 5) @end group @group @@ -1150,7 +1155,7 @@ Rearrangement @example @group -(setq x '(1 2 3)) +(setq x (list 1 2 3)) @result{} (1 2 3) @end group @group @@ -1163,11 +1168,13 @@ Rearrangement @end group @end example -However, the other arguments (all but the last) must be lists. +However, the other arguments (all but the last) should be mutable lists. -A common pitfall is to use a quoted constant list as a non-last -argument to @code{nconc}. If you do this, your program will change -each time you run it! Here is what happens: +A common pitfall is to use a constant list as a non-last +argument to @code{nconc}. If you do this, the resulting behavior +is undefined. It is possible that your program will change +each time you run it! Here is what might happen (though this +is not guaranteed to happen): @smallexample @group @@ -1270,7 +1277,7 @@ Sets And Lists @example @group -(setq sample-list '(a b c (4))) +(setq sample-list (list 'a 'b 'c '(4))) @result{} (a b c (4)) @end group @group @@ -1303,12 +1310,12 @@ Sets And Lists (setq flowers (delq 'rose flowers)) @end example -In the following example, the @code{(4)} that @code{delq} attempts to match -and the @code{(4)} in the @code{sample-list} are not @code{eq}: +In the following example, the @code{(list 4)} that @code{delq} attempts to match +and the @code{(4)} in the @code{sample-list} are @code{equal} but not @code{eq}: @example @group -(delq '(4) sample-list) +(delq (list 4) sample-list) @result{} (a c (4)) @end group @end example @@ -1324,7 +1331,7 @@ Sets And Lists @example @group -(setq sample-list '(a b c a b c)) +(setq sample-list (list 'a 'b 'c 'a 'b 'c)) @result{} (a b c a b c) @end group @group @@ -1349,12 +1356,12 @@ Sets And Lists @example @group -(memql 1.2 '(1.1 1.2 1.3)) ; @r{@code{1.2} and @code{1.2} are @code{eql}.} +(memql 1.2 '(1.1 1.2 1.3)) ; @r{@code{1.2} and @code{1.2} must be @code{eql}.} @result{} (1.2 1.3) @end group @group -(memq 1.2 '(1.1 1.2 1.3)) ; @r{@code{1.2} and @code{1.2} are not @code{eq}.} - @result{} nil +(memq 1.2 '(1.1 1.2 1.3)) ; @r{@code{1.2} and @code{1.2} need not be @code{eq}.} + @result{} nil ; @r{... or it might be @code{(1.2 1.3)}.} @end group @end example @end defun @@ -1373,11 +1380,11 @@ Sets And Lists @example @group -(member '(2) '((1) (2))) ; @r{@code{(2)} and @code{(2)} are @code{equal}.} +(member (list 2) '((1) (2))) ; @r{@code{(list 2)} and @code{(2)} are @code{equal}.} @result{} ((2)) @end group @group -(memq '(2) '((1) (2))) ; @r{@code{(2)} and @code{(2)} are not @code{eq}.} +(memq (list 2) '((1) (2))) ; @r{@code{(list 2)} and @code{(2)} are not @code{eq}.} @result{} nil @end group @group @@ -1407,7 +1414,7 @@ Sets And Lists @example @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(2) l) @result{} ((1)) l @@ -1416,7 +1423,7 @@ Sets And Lists ;; @r{write @code{(setq l (delete '(2) l))}.} @end group @group -(setq l '((2) (1) (2))) +(setq l (list '(2) '(1) '(2))) (delete '(1) l) @result{} ((2) (2)) l @@ -1619,7 +1626,7 @@ Association Lists ("compound leaves" . horsechestnut))) (assq "simple leaves" leaves) - @result{} nil + @result{} @r{Unspecified; might be @code{nil} or non-@code{nil}.} (assoc "simple leaves" leaves) @result{} ("simple leaves" . oak) @end smallexample @@ -1759,7 +1766,7 @@ Association Lists than looking at the saved value of @var{alist}. @example -(setq alist '((foo 1) (bar 2) (foo 3) (lose 4))) +(setq alist (list '(foo 1) '(bar 2) '(foo 3) '(lose 4))) @result{} ((foo 1) (bar 2) (foo 3) (lose 4)) (assq-delete-all 'foo alist) @result{} ((bar 2) (lose 4)) @@ -1926,7 +1933,7 @@ Plist Access in the place where you got @var{plist}. For example, @example -(setq my-plist '(bar t foo 4)) +(setq my-plist (list 'bar t 'foo 4)) @result{} (bar t foo 4) (setq my-plist (plist-put my-plist 'foo 69)) @result{} (bar t foo 69) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1c4e7e4d4e..1d5b2c690f 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -46,6 +46,10 @@ Lisp Data Types Lisp variables can only take on values of a certain type. @xref{Variables with Restricted Values}.) + Some Lisp objects are @dfn{constant}: their values should never change. +Others are @dfn{mutable}: their values can be changed via destructive +operations that involve side effects. + This chapter describes the purpose, printed representation, and read syntax of each of the standard types in GNU Emacs Lisp. Details on how to use these types can be found in later chapters. @@ -59,6 +63,7 @@ Lisp Data Types * Circular Objects:: Read syntax for circular structure. * Type Predicates:: Tests related to types. * Equality Predicates:: Tests of equality between any two objects. +* Constants and Mutability:: Whether an object's value can change. @end menu @node Printed Representation @@ -2373,3 +2378,52 @@ Equality Predicates @end group @end example @end defun + +@node Constants and Mutability +@section Constants and Mutability +@cindex constants +@cindex mutable objects + + Some Lisp objects are constant: their values should never change +during a single execution of Emacs running well-behaved Lisp code. +For example, you can create a new integer by calculating one, but you +cannot modify the value of an existing integer. + + Other Lisp objects are mutable: it is safe to change their values +via destructive operations involving side effects. For example, an +existing marker can be changed by moving the marker to point to +somewhere else. + + Although all numbers are constants and all markers are +mutable, some types contain both constant and mutable members. These +types include conses, vectors, strings, and symbols. For example, the string +literal @code{"aaa"} yields a constant string, whereas the function +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 part of an expression +that is evaluated. 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 +resulting behavior is undefined: the Lisp interpreter might or might +not detect the error, and if it does not detect the error the +interpreter can behave unpredictably thereafter. Another way to put +this is that although mutable objects are safe to change and constant +variables reliably prevent attempts to change them, other constants +are not safely mutable: if a misbehaving program tries to change such a +constant then the constant's value might actually change, or the +program might crash or worse. This problem occurs +with types that have both constant and mutable members, and that have +mutators like @code{setcar} and @code{aset} that are valid on mutable +objects but hazardous on constants. + + When the same constant occurs multiple times in a program, the Lisp +interpreter might save time or space by reusing existing constants or +constant components. For example, @code{(eq "abc" "abc")} returns +@code{t} if the interpreter creates only one instance of the string +constant @code{"abc"}, and returns @code{nil} if it creates two +instances. Lisp programs should be written so that they work +regardless of whether this optimization is in use. diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index d89aa31e4c..1cb0d05cc7 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ Sequence Functions @example @group -(setq bar '(1 2)) +(setq bar (list 1 2)) ; @r{Create a mutable list.} @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) +(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Sequence Functions @example @group -(setq x '(a b c)) +(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ Sequence Functions For the vector, it is even simpler because you don't need setq: @example -(setq x [1 2 3 4]) +(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -330,7 +330,7 @@ Sequence Functions Note that unlike @code{reverse}, this function doesn't work with strings. Although you can alter string data by using @code{aset}, it is strongly -encouraged to treat strings as immutable. +encouraged to treat strings as immutable even when they are mutable. @end defun @@ -374,7 +374,7 @@ Sequence Functions @example @group -(setq nums '(1 3 2 6 5 4 0)) +(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1228,7 @@ Array Functions @example @group -(setq w [foo bar baz]) +(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1237,7 +1237,8 @@ Array Functions @end group @group -(setq x "asdfasfd") +;; @r{@code{copy-sequence} creates a mutable string.} +(setq x (copy-sequence "asdfasfd")) @result{} "asdfasfd" (aset x 3 ?Z) @result{} 90 @@ -1246,6 +1247,10 @@ Array Functions @end group @end example +The @var{array} should be mutable; that is, it should not be a constant, +such as the constants created via quoting or via self-evaluating forms. +@xref{Constants and Mutability}. + If @var{array} is a string and @var{object} is not a character, a @code{wrong-type-argument} error results. The function converts a unibyte string to multibyte if necessary to insert a character. @@ -1257,7 +1262,8 @@ Array Functions @example @group -(setq a [a b c d e f g]) +;; @r{Create a mutable vector and then fill it with zeros.} +(setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @result{} [0 0 0 0 0 0 0] @@ -1265,7 +1271,8 @@ Array Functions @result{} [0 0 0 0 0 0 0] @end group @group -(setq s "When in the course") +;; @r{Create a mutable string and then fill it with "-".} +(setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) @result{} "------------------" @@ -1302,7 +1309,9 @@ Vectors A vector, like a string or a number, is considered a constant for evaluation: the result of evaluating it is the same vector. This does not evaluate or even examine the elements of the vector. -@xref{Self-Evaluating Forms}. +@xref{Self-Evaluating Forms}. Vectors written with square brackets +are constants and should not be modified via @code{aset} or other +destructive operations. @xref{Constants and Mutability}. Here are examples illustrating these principles: diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi index 14cabc5d79..a4c9c2549c 100644 --- a/doc/lispref/strings.texi +++ b/doc/lispref/strings.texi @@ -51,10 +51,8 @@ String Basics operate on them with the general array and sequence functions documented in @ref{Sequences Arrays Vectors}. For example, you can access or change individual characters in a string using the functions @code{aref} -and @code{aset} (@pxref{Array Functions}). However, note that -@code{length} should @emph{not} be used for computing the width of a -string on display; use @code{string-width} (@pxref{Size of Displayed -Text}) instead. +and @code{aset} (@pxref{Array Functions}). However, you should not +try to change the contents of constant strings (@pxref{Modifying Strings}). There are two text representations for non-@acronym{ASCII} characters in Emacs strings (and in buffers): unibyte and multibyte. @@ -89,6 +87,9 @@ String Basics for information about the syntax of characters and strings. @xref{Non-ASCII Characters}, for functions to convert between text representations and to encode and decode character codes. +Also, note that @code{length} should @emph{not} be used for computing +the width of a string on display; use @code{string-width} (@pxref{Size +of Displayed Text}) instead. @node Predicates for Strings @section Predicates for Strings @@ -380,6 +381,11 @@ Modifying Strings @cindex modifying strings @cindex string modification + You can alter the contents of a mutable string via operations +described in this section. However, you should not try to use these +operations to alter the contents of a constant string. +@xref{Constants and Mutability}. + The most basic way to alter the contents of an existing string is with @code{aset} (@pxref{Array Functions}). @code{(aset @var{string} @var{idx} @var{char})} stores @var{char} into @var{string} at index @@ -591,7 +597,7 @@ Text Comparison @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp) @result{} ("11" "1 1" "1.1" "12" "1 2" "1.2") @end group @end example @@ -608,7 +614,7 @@ Text Comparison @example @group -(sort '("11" "12" "1 1" "1 2" "1.1" "1.2") +(sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX"))) @result{} ("1 1" "1 2" "1.1" "1.2" "11" "12") @end group ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 16:39 ` Mattias Engdegård 2020-04-24 16:46 ` Dmitry Gutov @ 2020-04-24 17:18 ` Drew Adams 2020-04-25 3:38 ` Richard Stallman 2 siblings, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-04-24 17:18 UTC (permalink / raw) To: Mattias Engdegård, Richard Stallman Cc: Michael Heerdegen, ke.vigouroux, eggert, 40671 > > It seems strange to use the terms "constant" and "mutable" to > > describe whether modifying its contents is something you had > > better avoid. I think people will find that terminology > > confusing. Normally "mutable" means that you CAN change it, > > not that it is OK to change it. > > What is the difference between CANNOT and > SHOULD NOT, operationally? To the user, nothing; there is no gain from > disobeying our advice. No. To the user: something. And the negative effects might not be immediately noticeable. If we say that you can't modify XYZ there's no need for you to pay attention, learn about the gotcha, and try to avoid modifying XYZ. The burden here is on the user (unfortunately). Emacs Lisp doesn't protect you from doing what you'd be told you "cannot" do. It's up to you to know when you might be stumbling onto this pitfall and avoid it. Telling users they _can't_ fall into this pit is like telling someone it's impossible for their car to go through a red light. Nope, they're the driver, and the message should be, "Don't drive through a red light." ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-24 16:39 ` Mattias Engdegård 2020-04-24 16:46 ` Dmitry Gutov 2020-04-24 17:18 ` Drew Adams @ 2020-04-25 3:38 ` Richard Stallman 2020-04-25 18:26 ` Paul Eggert 2 siblings, 1 reply; 170+ messages in thread From: Richard Stallman @ 2020-04-25 3:38 UTC (permalink / raw) To: Mattias EngdegÃ¥rd Cc: michael_heerdegen, ke.vigouroux, eggert, 40671 [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] > That is an interesting point. What is the difference between > CANNOT and SHOULD NOT, operationally? To the user, nothing; there > is no gain from disobeying our advice. It makes a big practical difference to programmers. CANNOT means "If you try to chsnge it, it won't change", and probably also "That will trigger a diagnostic." SHOULOD NOT means "if you try to chsnge it, it will give you no diagnostic and the value will seem to have changed, but afterward bizarre things may happen." -- Dr Richard Stallman Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 3:38 ` Richard Stallman @ 2020-04-25 18:26 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-25 18:26 UTC (permalink / raw) To: rms, Mattias Engdegård; +Cc: michael_heerdegen, ke.vigouroux, 40671 On 4/24/20 8:38 PM, Richard Stallman wrote: > SHOULOD NOT means "if you try to change it, it will give you no > diagnostic and the value will seem to have changed, but afterward > bizarre things may happen." Here SHOULD NOT simply means "if you try to change it, afterward bizarre things may happen". This includes the meaning you gave, and also includes some other meanings. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-23 0:49 ` Michael Heerdegen 2020-04-24 2:36 ` Richard Stallman @ 2020-04-25 2:22 ` Paul Eggert 2020-04-25 6:00 ` Andreas Schwab 2020-04-28 23:52 ` Michael Heerdegen 1 sibling, 2 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-25 2:22 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux [-- Attachment #1: Type: text/plain, Size: 1399 bytes --] On 4/22/20 5:49 PM, Michael Heerdegen wrote: > + 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. > > `eval' is used quite rarely. Can what you describe happen under other > circumstances, or does it only happen to `eval'? E.g. what about this > case for example: > > (let ((l (list 1 2 3))) > (funcall (lambda () l))) > > Has the list become a constant? No, because the list is not part of the expression that is being evaluated. However, something like this could cause trouble: (let ((l (list 'lambda '(x) '(setcdr l x)))) (eval (list l l))) because it modifies the list l while it is evaluating it. (As it happens, this code behaves differently in Emacs 26 than it does in Emacs 27 - that's what you can get with undefined behavior....) > Maybe I misread "might be executed" as > "might be executed in the future" and you actually meant something like > "might (currently) be executed (as part of the expression the > interpreter currently executes). > > BTW, speaking about Lisp the term "evaluate" is probably preferable to > "execute" I think. Both good points. The word "executed" is already gone from the manual, and I installed the attached patch to try to address the other point. [-- Attachment #2: 0001-Tweak-mutability-doc-a-bit-more.patch --] [-- Type: text/x-patch, Size: 1118 bytes --] From 49bc5a63f7d6178f136d9e28bcacda3acfc375d3 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Fri, 24 Apr 2020 19:19:31 -0700 Subject: [PATCH] Tweak mutability doc a bit more Inspired by a comment from Michael Heerdegen (Bug#40671#114). * doc/lispref/objects.texi (Constants and Mutability): Tweak further. --- doc/lispref/objects.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 1eda94ab63..b4e9ff4411 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -2401,8 +2401,8 @@ 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 a program should not modify an object + A mutable object can become constant if it is part of an expression +that is evaluated, because a program should not modify an object that is being evaluated. The reverse does not occur: constant objects should stay constant. -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 2:22 ` Paul Eggert @ 2020-04-25 6:00 ` Andreas Schwab 2020-04-25 18:23 ` Paul Eggert 2020-04-28 23:52 ` Michael Heerdegen 1 sibling, 1 reply; 170+ messages in thread From: Andreas Schwab @ 2020-04-25 6:00 UTC (permalink / raw) To: Paul Eggert Cc: Michael Heerdegen, Mattias Engdegård, 40671, ke.vigouroux On Apr 24 2020, Paul Eggert wrote: > diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi > index 1eda94ab63..b4e9ff4411 100644 > --- a/doc/lispref/objects.texi > +++ b/doc/lispref/objects.texi > @@ -2401,8 +2401,8 @@ 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 a program should not modify an object > + A mutable object can become constant if it is part of an expression > +that is evaluated, because a program should not modify an object > that is being evaluated. The reverse does not occur: constant objects "that is evaluated ... that is being evaluated" is saying the same thing twice. Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510 2552 DF73 E780 A9DA AEC1 "And now for something completely different." ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 6:00 ` Andreas Schwab @ 2020-04-25 18:23 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-25 18:23 UTC (permalink / raw) To: Andreas Schwab Cc: Michael Heerdegen, Mattias Engdegård, 40671, ke.vigouroux [-- Attachment #1: Type: text/plain, Size: 181 bytes --] On 4/24/20 11:00 PM, Andreas Schwab wrote: > "that is evaluated ... that is being evaluated" is saying the same thing > twice. Thanks for catching that; I installed the attached. [-- Attachment #2: 0001-Remove-doc-duplication.patch --] [-- Type: text/x-patch, Size: 1027 bytes --] From 9621a4840a27d2fb0283a4faa5aadd7febaeaf6b Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sat, 25 Apr 2020 11:22:01 -0700 Subject: [PATCH] Remove doc duplication * doc/lispref/objects.texi (Constants and Mutability): Remove duplication. From a suggestion by Andreas Schwab (Bug#40671#150). --- doc/lispref/objects.texi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index b4e9ff4411..1d5b2c690f 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -2402,8 +2402,7 @@ Constants and Mutability changed via later calls to @code{aset}. A mutable object can become constant if it is part of an expression -that is evaluated, because a program should not modify an object -that is being evaluated. The reverse does not occur: constant objects +that is evaluated. The reverse does not occur: constant objects should stay constant. Trying to modify a constant variable signals an error -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-25 2:22 ` Paul Eggert 2020-04-25 6:00 ` Andreas Schwab @ 2020-04-28 23:52 ` Michael Heerdegen 1 sibling, 0 replies; 170+ messages in thread From: Michael Heerdegen @ 2020-04-28 23:52 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Paul Eggert <eggert@cs.ucla.edu> writes: > > (let ((l (list 1 2 3))) > > (funcall (lambda () l))) > > > > Has the list become a constant? > > No, because the list is not part of the expression that is being evaluated. > However, something like this could cause trouble: > > (let ((l (list 'lambda '(x) '(setcdr l x)))) > (eval (list l l))) FWIW, I asked also because `funcall' seems, at least AFAIU, share some code with `eval', and with lexical-binding on the lambda gets transformed into something that does include the original list, so the list becomes part of the evaluated expression. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 23:45 ` Michael Heerdegen 2020-04-20 0:24 ` Paul Eggert @ 2020-04-21 1:25 ` Michael Heerdegen 2020-04-21 2:20 ` Paul Eggert 1 sibling, 1 reply; 170+ messages in thread From: Michael Heerdegen @ 2020-04-21 1:25 UTC (permalink / raw) To: Paul Eggert; +Cc: Mattias Engdegård, 40671, ke.vigouroux Michael Heerdegen <michael_heerdegen@web.de> writes: > > Yes, in hindsight I suppose you're right. If you like I can revert the > > changes now. > > I can't estimate, for me it is enough if you are willing to revert if > there is no consent and we discuss all of this now. But regardless of the impression that your chosen course of action gives (my own course of action often gives bad impressions for other reasons, and I don't mean to say that my impression is only bad, just a bit like...blindside?), it is harder now to review and estimate your changes in sum, and this is not good for the exchange of views that I think would be very valuable in this case. Michael. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-21 1:25 ` Michael Heerdegen @ 2020-04-21 2:20 ` Paul Eggert 0 siblings, 0 replies; 170+ messages in thread From: Paul Eggert @ 2020-04-21 2:20 UTC (permalink / raw) To: Michael Heerdegen; +Cc: Mattias Engdegård, 40671, ke.vigouroux On 4/20/20 6:25 PM, Michael Heerdegen wrote: > it is harder now to review and estimate your changes > in sum Yes, software archaeology can be a bit of a pain. You could try running this shell command: git diff eebfb72c906755c0a80d92c11deee7ac9faf5f4b^..05089a4d65831c5e873956f5f2d92a3d5672d405 -- doc/lispintro doc/lispref/elisp.texi doc/lispref/eval.texi doc/lispref/keymaps.texi doc/lispref/lists.texi doc/lispref/objects.texi doc/lispref/sequences.texi doc/lispref/strings.texi though if the doc evolves further the command could get longer.... ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 22:41 ` Paul Eggert 2020-04-19 23:45 ` Michael Heerdegen @ 2020-04-20 6:02 ` Drew Adams 1 sibling, 0 replies; 170+ messages in thread From: Drew Adams @ 2020-04-20 6:02 UTC (permalink / raw) To: Paul Eggert, Michael Heerdegen Cc: Mattias Engdegård, 40671, ke.vigouroux > the reason one shouldn't modify byte-code objects > is ... because doing so can make Emacs crash. Really? If something can make Emacs crash it means there's a bug; that's all. If there's a bug we shouldn't document the bugged behavior (it should be fixed), and we especially shouldn't, in the doc, say "you should [not] do XYZ" because it can make Emacs crash. ^ permalink raw reply [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 13:56 ` Eli Zaretskii 2020-04-19 16:59 ` Mattias Engdegård @ 2020-04-19 20:45 ` Paul Eggert 2020-04-20 14:10 ` Eli Zaretskii 1 sibling, 1 reply; 170+ messages in thread From: Paul Eggert @ 2020-04-19 20:45 UTC (permalink / raw) To: Eli Zaretskii; +Cc: mattiase, 40671, ke.vigouroux [-- Attachment #1: Type: text/plain, Size: 2401 bytes --] On 4/19/20 6:56 AM, Eli Zaretskii wrote: > How do you know the patch addresses my concerns I don't know that; I merely wrote that the patch should address the points you raised earlier. The goal was to improve documentation that was obviously deficient in this area - there's no serious dispute about that. The changes I installed were intended to be an improvement and have been found so by others - if you disagree, please feel free to revert or improve them. Obviously the documentation is not perfect in this area and further improvements would be welcome. > As Štěpán points out, not all of the examples need these changes. I installed further changes that should address Štěpán's comments. > For example, the node "Sets and Lists" now sometimes uses literal > lists and sometimes non-literal ones -- without any explanation why. > Likewise in "Association Lists" and "Sequence Functions". This was in response to your request to not change examples if the examples didn't strictly need the changes. Although I preferred Mattias's original proposal because it switched to the (list ...) style more uniformly, the patch I installed mixed the '(...) and (list ...) styles because I thought that was what you were asking for. I installed the attached patch, which attempts to address this issue by adding comments that try to explain why (list ...) is needed sometimes. However, in hindsight perhaps we should go back to the style used in Mattias's proposal, as it's simpler and more consistent and doesn't distract the reader from the focus of the documentation. Going back to Mattias's style would let us remove some of the comments that the attached patch inserts. >> @example >> @group >> -(delq 'a '(a b c)) @equiv{} (cdr '(a b c)) >> +(equal >> + (delq 'a (list 'a 'b 'c)) >> + (cdr (list 'a 'b 'c))) >> @end group > > And here you simply changed the meaning of the example: @equiv{} is > not the same as 'equal'. Ah, I missed on that one. Thanks for pointing it out. I reverted that change in the attached patch. As you note, it's not essential that the list be modifiable in this particular example. That being said, the documentation should not suggest that it's OK to use a destructive operation like delq on a constant, so further improvements would be helpful here if someone can find the time. [-- Attachment #2: 0001-Improve-mutability-doc.patch --] [-- Type: text/x-patch, Size: 4434 bytes --] From 5805df74f5b919a3f67f3f7d31d6e600e1564e4e Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Sun, 19 Apr 2020 13:22:10 -0700 Subject: [PATCH] Improve mutability doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See Eli Zaretskii’s suggestions (Bug#40671#33). * doc/lispref/lists.texi (Setcar, Setcdr, Rearrangement): * doc/lispref/sequences.texi (Sequence Functions) (Array Functions): Add commentary to examples. * doc/lispref/lists.texi (Sets And Lists): Revert change to delq example. --- doc/lispref/lists.texi | 16 +++++++--------- doc/lispref/sequences.texi | 14 ++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/doc/lispref/lists.texi b/doc/lispref/lists.texi index f1acc85616..1125af7bec 100644 --- a/doc/lispref/lists.texi +++ b/doc/lispref/lists.texi @@ -911,7 +911,7 @@ value @var{object}. For example: @example @group -(setq x (list 1 2)) +(setq x (list 1 2)) ; @r{Create a mutable list.} @result{} (1 2) @end group @group @@ -931,7 +931,7 @@ these lists. Here is an example: @example @group -;; @r{Create two lists that are partly shared.} +;; @r{Create two mutable lists that are partly shared.} (setq x1 (list 'a 'b 'c)) @result{} (a b c) (setq x2 (cons 'z (cdr x1))) @@ -1022,11 +1022,11 @@ reached via the @sc{cdr}. @example @group -(setq x (list 1 2 3)) +(setq x (list 1 2 3)) ; @r{Create a mutable list.} @result{} (1 2 3) @end group @group -(setcdr x '(4)) +(setcdr x '(4)) ; @r{Modify the list's tail to be a constant list.} @result{} (4) @end group @group @@ -1135,11 +1135,11 @@ Unlike @code{append} (@pxref{Building Lists}), the @var{lists} are @example @group -(setq x (list 1 2 3)) +(setq x (list 1 2 3)) ; @r{Create a mutable list.} @result{} (1 2 3) @end group @group -(nconc x '(4 5)) +(nconc x '(4 5)) ; @r{Modify the list's tail to be a constant list.} @result{} (1 2 3 4 5) @end group @group @@ -1267,9 +1267,7 @@ after those elements. For example: @example @group -(equal - (delq 'a (list 'a 'b 'c)) - (cdr (list 'a 'b 'c))) +(delq 'a '(a b c)) @equiv{} (cdr '(a b c)) @end group @end example diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 62d60156fb..1cb0d05cc7 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -183,11 +183,11 @@ for other ways to copy sequences. @example @group -(setq bar (list 1 2)) +(setq bar (list 1 2)) ; @r{Create a mutable list.} @result{} (1 2) @end group @group -(setq x (vector 'foo bar)) +(setq x (vector 'foo bar)) ; @r{Create a mutable vector.} @result{} [foo (1 2)] @end group @group @@ -278,7 +278,7 @@ Unlike @code{reverse} the original @var{sequence} may be modified. @example @group -(setq x (list 'a 'b 'c)) +(setq x (list 'a 'b 'c)) ; @r{Create a mutable list.} @result{} (a b c) @end group @group @@ -320,7 +320,7 @@ presented graphically: For the vector, it is even simpler because you don't need setq: @example -(setq x (copy-sequence [1 2 3 4])) +(setq x (copy-sequence [1 2 3 4])) ; @r{Create a mutable vector.} @result{} [1 2 3 4] (nreverse x) @result{} [4 3 2 1] @@ -374,7 +374,7 @@ appears in a different position in the list due to the change of @example @group -(setq nums (list 1 3 2 6 5 4 0)) +(setq nums (list 1 3 2 6 5 4 0)) ; @r{Create a mutable list.} @result{} (1 3 2 6 5 4 0) @end group @group @@ -1228,7 +1228,7 @@ This function sets the @var{index}th element of @var{array} to be @example @group -(setq w (vector 'foo 'bar 'baz)) +(setq w (vector 'foo 'bar 'baz)) ; @r{Create a mutable vector.} @result{} [foo bar baz] (aset w 0 'fu) @result{} fu @@ -1262,6 +1262,7 @@ each element of @var{array} is @var{object}. It returns @var{array}. @example @group +;; @r{Create a mutable vector and then fill it with zeros.} (setq a (copy-sequence [a b c d e f g])) @result{} [a b c d e f g] (fillarray a 0) @@ -1270,6 +1271,7 @@ a @result{} [0 0 0 0 0 0 0] @end group @group +;; @r{Create a mutable string and then fill it with "-".} (setq s (copy-sequence "When in the course")) @result{} "When in the course" (fillarray s ?-) -- 2.17.1 ^ permalink raw reply related [flat|nested] 170+ messages in thread
* bug#40671: [DOC] modify literal objects 2020-04-19 20:45 ` Paul Eggert @ 2020-04-20 14:10 ` Eli Zaretskii 0 siblings, 0 replies; 170+ messages in thread From: Eli Zaretskii @ 2020-04-20 14:10 UTC (permalink / raw) To: Paul Eggert; +Cc: mattiase, 40671, ke.vigouroux > Cc: mattiase@acm.org, 40671@debbugs.gnu.org, ke.vigouroux@laposte.net > From: Paul Eggert <eggert@cs.ucla.edu> > Date: Sun, 19 Apr 2020 13:45:07 -0700 > > > For example, the node "Sets and Lists" now sometimes uses literal > > lists and sometimes non-literal ones -- without any explanation why. > > Likewise in "Association Lists" and "Sequence Functions". > > This was in response to your request to not change examples if the examples > didn't strictly need the changes. Although I preferred Mattias's original > proposal because it switched to the (list ...) style more uniformly, the patch I > installed mixed the '(...) and (list ...) styles because I thought that was what > you were asking for. > > I installed the attached patch, which attempts to address this issue by adding > comments that try to explain why (list ...) is needed sometimes. This is better, thanks. Although my feeling that we complicated what used to be a simple section is still here. > However, in > hindsight perhaps we should go back to the style used in Mattias's proposal, as > it's simpler and more consistent and doesn't distract the reader from the focus > of the documentation. Going back to Mattias's style would let us remove some of > the comments that the attached patch inserts. I think consistency should take a back seat in these situations. Clarity and easiness of reading and understanding are much more important. > As you note, it's not essential that the list be modifiable in this particular > example. That being said, the documentation should not suggest that it's OK to > use a destructive operation like delq on a constant, so further improvements > would be helpful here if someone can find the time. But that's exactly the disagreement between us: you think that each example must be perfect in that it follows all of the principles ever mentioned anywhere in the manual, and shouldn't go anywhere near the places which we explain elsewhere are, or might be, dangerous. The problem with that is that if you want to be absolutely correct and rigorous, you will more often than not be unable to say anything, or will produce code samples that are so arcane to the beginner that they will squarely miss their point. Witness your dialogue with Michael Heerdegen about related issues. I think there's no need to assign such crucial importance to every example. If it is easy to make the example more correct by small changes, we should consider doing that. But adding the likes of copy-list to an example that's supposed to show how to delete a list member is IMO a terrible overkill, and makes the example harder to understand: a reader who just learned about making and modifying lists suddenly needs to know what copy-list does (e.g., is it a deep copy or not?). IMO and IME, this kind of rigor is self-defeating, unless it comes in a special section marked "Advanced" or somesuch. Bottom line: IMO the manual should introduce the material gradually; it is okay to defer some subtle aspects to later sections, and initially simply disregard them. E.g., in a section that describes arithmetic operators like '+' in C to someone who is supposed to be a C beginner, you won't right away talk about integer overflow and the subsequent danger of crashing the system, and you won't tell the reader "don't ever use '+', use INT_ADD_WRAPV instead", nor will you replace examples that use '+' with that macro, would you? ^ permalink raw reply [flat|nested] 170+ messages in thread
end of thread, other threads:[~2020-05-17 16:38 UTC | newest] Thread overview: 170+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-04-16 19:28 bug#40671: [DOC] modify literal objects Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 2020-04-17 16:09 ` Mattias Engdegård 2020-04-17 16:37 ` Mattias Engdegård 2020-04-17 17:27 ` Eli Zaretskii 2020-04-18 20:10 ` Paul Eggert 2020-04-18 21:54 ` Drew Adams 2020-04-19 2:39 ` Noam Postavsky 2020-04-19 20:39 ` Paul Eggert 2020-04-19 21:01 ` Drew Adams 2020-04-19 21:16 ` Paul Eggert 2020-04-19 22:24 ` Drew Adams 2020-04-19 22:51 ` Paul Eggert 2020-04-20 5:32 ` Drew Adams 2020-04-22 17:36 ` Paul Eggert 2020-05-01 3:03 ` Dmitry Gutov 2020-05-01 5:16 ` Drew Adams 2020-05-01 21:46 ` Paul Eggert 2020-05-01 23:37 ` Dmitry Gutov 2020-04-19 2:26 ` Richard Stallman 2020-04-19 13:56 ` Eli Zaretskii 2020-04-19 16:59 ` Mattias Engdegård 2020-04-19 19:21 ` Eli Zaretskii 2020-04-19 21:02 ` Paul Eggert 2020-04-19 21:11 ` Drew Adams 2020-04-19 21:57 ` Michael Heerdegen 2020-04-19 22:41 ` Paul Eggert 2020-04-19 23:45 ` Michael Heerdegen 2020-04-20 0:24 ` Paul Eggert 2020-04-20 0:53 ` Michael Heerdegen 2020-04-20 3:23 ` Paul Eggert 2020-04-20 3:36 ` Michael Heerdegen 2020-04-22 6:30 ` Paul Eggert 2020-04-20 5:54 ` Drew Adams 2020-04-22 17:21 ` Paul Eggert 2020-04-23 0:49 ` Michael Heerdegen 2020-04-24 2:36 ` Richard Stallman 2020-04-24 15:08 ` Drew Adams 2020-04-25 1:58 ` Paul Eggert 2020-04-24 16:39 ` Mattias Engdegård 2020-04-24 16:46 ` Dmitry Gutov 2020-04-25 2:21 ` Paul Eggert 2020-04-25 2:40 ` Dmitry Gutov 2020-04-25 3:20 ` Paul Eggert 2020-04-25 19:30 ` Dmitry Gutov 2020-04-26 3:49 ` Paul Eggert 2020-04-26 14:03 ` Dmitry Gutov 2020-04-26 14:19 ` Eli Zaretskii 2020-04-26 14:34 ` Dmitry Gutov 2020-04-26 15:46 ` Eli Zaretskii 2020-04-26 16:02 ` Dmitry Gutov 2020-04-26 16:58 ` Eli Zaretskii 2020-04-26 17:39 ` Dmitry Gutov 2020-04-26 18:14 ` Eli Zaretskii 2020-04-26 18:32 ` Dmitry Gutov 2020-04-26 18:41 ` Eli Zaretskii 2020-04-26 18:53 ` Dmitry Gutov 2020-04-26 18:57 ` Paul Eggert 2020-04-26 19:22 ` Philipp Stephani 2020-04-26 20:14 ` Paul Eggert 2020-04-26 21:23 ` Dmitry Gutov 2020-04-26 23:13 ` Paul Eggert 2020-04-27 0:53 ` Dmitry Gutov 2020-04-27 1:49 ` Paul Eggert 2020-04-28 3:05 ` Dmitry Gutov 2020-04-28 8:17 ` Paul Eggert 2020-04-28 13:54 ` Dmitry Gutov 2020-04-28 17:59 ` Paul Eggert 2020-04-28 18:46 ` Dmitry Gutov 2020-04-28 19:20 ` Paul Eggert 2020-04-28 19:33 ` Dmitry Gutov 2020-04-28 20:09 ` Paul Eggert 2020-04-28 21:10 ` Dmitry Gutov 2020-04-28 23:10 ` Paul Eggert 2020-04-28 23:36 ` Dmitry Gutov 2020-04-28 23:53 ` Paul Eggert 2020-04-28 23:57 ` Dmitry Gutov 2020-04-28 23:53 ` Dmitry Gutov 2020-04-29 0:04 ` Paul Eggert 2020-04-29 0:14 ` Dmitry Gutov 2020-04-29 0:55 ` Drew Adams 2020-04-29 1:03 ` Dmitry Gutov 2020-04-29 1:15 ` Drew Adams 2020-04-29 1:27 ` Michael Heerdegen 2020-04-29 1:38 ` Paul Eggert 2020-04-29 4:36 ` Drew Adams 2020-04-29 16:18 ` Paul Eggert 2020-05-01 2:47 ` Richard Stallman 2020-05-01 6:23 ` Eli Zaretskii 2020-05-01 3:13 ` Dmitry Gutov 2020-05-01 5:15 ` Drew Adams 2020-05-01 21:40 ` Paul Eggert 2020-05-01 22:05 ` Drew Adams 2020-05-01 22:28 ` Paul Eggert 2020-05-02 1:07 ` Dmitry Gutov 2020-05-02 6:28 ` Paul Eggert 2020-05-02 15:42 ` Dmitry Gutov 2020-05-02 19:35 ` Paul Eggert 2020-05-03 1:30 ` Dmitry Gutov 2020-05-03 7:40 ` Paul Eggert 2020-05-03 16:44 ` Dmitry Gutov 2020-05-03 20:48 ` Paul Eggert 2020-05-03 22:17 ` Dmitry Gutov 2020-05-03 22:18 ` Dmitry Gutov 2020-05-03 22:39 ` Paul Eggert 2020-05-03 22:53 ` Dmitry Gutov 2020-05-03 23:10 ` Paul Eggert 2020-05-04 10:16 ` Dmitry Gutov 2020-05-04 17:52 ` Paul Eggert 2020-05-05 1:39 ` Dmitry Gutov 2020-05-05 6:09 ` Paul Eggert 2020-05-05 12:38 ` Dmitry Gutov 2020-05-09 6:10 ` Paul Eggert 2020-05-10 3:13 ` Dmitry Gutov 2020-05-10 13:34 ` Dmitry Gutov 2020-05-10 17:29 ` Paul Eggert 2020-05-11 0:00 ` Michael Heerdegen 2020-05-11 0:26 ` Dmitry Gutov 2020-05-11 1:47 ` Drew Adams 2020-05-11 1:54 ` Dmitry Gutov 2020-05-11 2:33 ` Drew Adams 2020-05-11 2:56 ` Michael Heerdegen 2020-05-11 4:21 ` Drew Adams 2020-05-11 4:51 ` Michael Heerdegen 2020-05-11 6:28 ` Paul Eggert 2020-05-11 13:57 ` Noam Postavsky 2020-05-11 22:36 ` Michael Heerdegen 2020-05-11 22:30 ` Michael Heerdegen 2020-05-12 3:20 ` Richard Stallman 2020-05-12 4:24 ` Michael Heerdegen 2020-05-13 3:57 ` Richard Stallman 2020-05-13 5:05 ` Michael Heerdegen 2020-05-14 5:14 ` Richard Stallman [not found] ` <05BEF593-F16A-4DEE-98BC-653221F1F9EE@acm.org> 2020-05-17 0:11 ` Paul Eggert 2020-05-17 9:43 ` Mattias Engdegård 2020-05-17 16:38 ` Paul Eggert 2020-05-11 1:53 ` Paul Eggert 2020-05-11 3:18 ` Michael Heerdegen 2020-05-11 0:44 ` Dmitry Gutov 2020-05-11 1:57 ` Paul Eggert 2020-05-12 1:59 ` Dmitry Gutov 2020-05-17 1:28 ` Paul Eggert 2020-05-17 5:02 ` Michael Heerdegen 2020-05-17 16:34 ` Paul Eggert 2020-05-17 12:39 ` Dmitry Gutov 2020-05-17 16:21 ` Paul Eggert 2020-05-05 17:40 ` Drew Adams 2020-05-05 18:49 ` Dmitry Gutov 2020-05-05 19:26 ` Drew Adams 2020-05-05 20:48 ` Kevin Vigouroux via Bug reports for GNU Emacs, the Swiss army knife of text editors 2020-05-09 5:57 ` Paul Eggert 2020-04-28 21:18 ` Dmitry Gutov 2020-04-28 17:25 ` Drew Adams 2020-04-28 17:47 ` Paul Eggert 2020-04-29 0:32 ` Michael Heerdegen 2020-04-29 1:40 ` Paul Eggert 2020-04-29 4:40 ` Michael Heerdegen 2020-04-29 8:01 ` Eli Zaretskii 2020-04-29 16:36 ` Paul Eggert 2020-04-24 17:18 ` Drew Adams 2020-04-25 3:38 ` Richard Stallman 2020-04-25 18:26 ` Paul Eggert 2020-04-25 2:22 ` Paul Eggert 2020-04-25 6:00 ` Andreas Schwab 2020-04-25 18:23 ` Paul Eggert 2020-04-28 23:52 ` Michael Heerdegen 2020-04-21 1:25 ` Michael Heerdegen 2020-04-21 2:20 ` Paul Eggert 2020-04-20 6:02 ` Drew Adams 2020-04-19 20:45 ` Paul Eggert 2020-04-20 14:10 ` Eli Zaretskii
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).