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

From: Paul Eggert <[email-masked]>
Date: Sat, 16 May 2020 17:11:29 -0700

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'.
From aed11100f8056804d2e438fc4e793dc099d0e06f Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
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