Make cl-gensym obsolete in favor of built-in gensym

* lisp/emacs-lisp/cl-macs.el (cl-gensym): Declare function
obsolete in favor of gensym, added in Emacs 26.1.  The only reason
for its existence is that it allows an integer argument, but
that's not really useful, so it's better to remove this complexity.
Ref: https://lists.gnu.org/r/emacs-devel/2017-09/msg00313.html
* doc/misc/cl.texi (Symbols, Creating Symbols, Efficiency Concerns)
(Obsolete Setf Customization): Don't document above obsolete function.
* lisp/emacs-lisp/cl-macs.el (cl--parse-loop-clause):
* lisp/emacs-lisp/edebug.el (edebug-make-form-wrapper):
* lisp/obsolete/cl.el (cl--function-convert, lexical-let):
* lisp/obsolete/thumbs.el (thumbs-temp-file):
* lisp/progmodes/eglot.el (eglot--lambda)
(eglot--when-live-buffer, eglot--when-buffer-window)
(eglot--collecting-xrefs, eglot--glob-parse):
* lisp/progmodes/flymake.el (flymake--run-backend):
* test/lisp/emacs-lisp/package-tests.el (with-package-test):
* test/lisp/progmodes/eglot-tests.el (eglot--guessing-contact):
* test/lisp/progmodes/elisp-mode-tests.el
(elisp-shorthand-read-buffer, elisp-shorthand-read-from-string): Prefer
plain gensym to cl-gensym in files that can depend on Emacs 26.1.
* lisp/jsonrpc.el (jsonrpc-lambda, jsonrpc-request): Prefer gensym to
cl-gensym only when defined, as this file supports Emacs 25.1
* test/lisp/emacs-lisp/cl-macs-tests.el (cl-lib-test-gensym): Simplify
test as 'should' no longer uses cl-gensym.
This commit is contained in:
Stefan Kangas 2025-02-25 00:12:00 +01:00
parent 1a22bc0fd6
commit 60b071e224
13 changed files with 43 additions and 63 deletions

View file

@ -2804,7 +2804,7 @@ missing from Emacs Lisp.
@menu
* Property Lists:: @code{cl-get}, @code{cl-remprop}, @code{cl-getf}, @code{cl-remf}.
* Creating Symbols:: @code{cl-gensym}, @code{cl-gentemp}.
* Creating Symbols:: @code{cl-gentemp}.
@end menu
@node Property Lists
@ -2892,30 +2892,10 @@ out the property and value cells.
@section Creating Symbols
@cindex gensym
@noindent
These functions create unique symbols, typically for use as
temporary variables.
@defun cl-gensym &optional x
This function creates a new, uninterned symbol (using @code{make-symbol})
with a unique name. (The name of an uninterned symbol is relevant
only if the symbol is printed.) By default, the name is generated
from an increasing sequence of numbers, @samp{G1000}, @samp{G1001},
@samp{G1002}, etc. If the optional argument @var{x} is a string, that
string is used as a prefix instead of @samp{G}. Uninterned symbols
are used in macro expansions for temporary variables, to ensure that
their names will not conflict with ``real'' variables in the user's
code.
(Internally, the variable @code{cl--gensym-counter} holds the counter
used to generate names. It is initialized with zero and incremented
after each use.)
@end defun
@defun cl-gentemp &optional x
This function is like @code{cl-gensym}, except that it produces a new
@emph{interned} symbol. If the symbol that is generated already
exists, the function keeps incrementing the counter and trying
This function is like the built-in @code{gensym}, except that it
produces a new @emph{interned} symbol. If the symbol that is generated
already exists, the function keeps incrementing the counter and trying
again until a new symbol is generated.
@end defun
@ -4419,18 +4399,18 @@ an expansion similar to:
@example
(cl-block nil
(let* ((x 0)
(G1004 nil))
(g1004 nil))
(while (< x 10)
(setq G1004 (cons x G1004))
(setq g1004 (cons x g1004))
(setq x (+ x 1)))
(nreverse G1004)))
(nreverse g1004)))
@end example
@noindent
will be inserted into the buffer. (The @code{cl-block} macro is
expanded differently in the interpreter and compiler, so
@code{cl-prettyexpand} just leaves it alone. The temporary
variable @code{G1004} was created by @code{cl-gensym}.)
variable @code{g1004} was created by @code{gensym}.)
If the optional argument @var{full} is true, then @emph{all}
macros are expanded, including @code{cl-block}, @code{cl-eval-when},
@ -5157,7 +5137,7 @@ temporary variables. In the setf-methods generated by
@code{defsetf}, the second return value is simply the list of
arguments in the place form, and the first return value is a
list of a corresponding number of temporary variables generated
by @code{cl-gensym}.
by @code{gensym}.
@end defmac
@node GNU Free Documentation License

View file

@ -540,6 +540,9 @@ It is an alias for the 'progn' special-form.
+++
*** 'cl-declare' is now obsolete; use 'defvar' instead.
+++
*** 'cl-gensym' is now obsolete; use 'gensym' instead.
** Whitespace
---

View file

@ -166,6 +166,7 @@ whether X is known at compile time, macroexpand it completely in
(defun cl-gensym (&optional prefix)
"Generate a new uninterned symbol.
The name is made by appending a number to PREFIX, default \"G\"."
(declare (obsolete gensym "31.1"))
(let ((pfix (if (stringp prefix) prefix "G"))
(num (if (integerp prefix) prefix
(prog1 cl--gensym-counter
@ -1270,10 +1271,10 @@ For more details, see Info node `(cl)Loop Facility'.
(let ((loop-for-bindings nil) (loop-for-sets nil) (loop-for-steps nil)
(ands nil))
(while
;; Use `cl-gensym' rather than `make-symbol'. It's important that
;; Use `gensym' rather than `make-symbol'. It's important that
;; (not (eq (symbol-name var1) (symbol-name var2))) because
;; these vars get added to the macro-environment.
(let ((var (or (pop cl--loop-args) (cl-gensym "--cl-var--"))))
(let ((var (or (pop cl--loop-args) (gensym "--cl-var--"))))
(setq word (pop cl--loop-args))
(if (eq word 'being) (setq word (pop cl--loop-args)))
(if (memq word '(the each)) (setq word (pop cl--loop-args)))

View file

@ -1369,7 +1369,7 @@ infinite loops when the code/environment contains a circular object.")
;; Set the name here if it was not set by edebug-make-enter-wrapper.
(setq edebug-def-name
(or edebug-def-name edebug-old-def-name (cl-gensym "edebug-anon")))
(or edebug-def-name edebug-old-def-name (gensym "edebug-anon")))
;; Add this def as a dependent of containing def. Buggy.
'(if (and edebug-containing-def-name

View file

@ -204,7 +204,8 @@ JSONRPC message."
;;;
(cl-defmacro jsonrpc-lambda (cl-lambda-list &body body)
(declare (indent 1) (debug (sexp &rest form)))
(let ((e (cl-gensym "jsonrpc-lambda-elem")))
(let ((e (funcall (if (fboundp 'gensym) 'gensym 'cl-gensym)
"jsonrpc-lambda-elem")))
`(lambda (,e) (apply (cl-function (lambda ,cl-lambda-list ,@body)) ,e))))
(defun jsonrpc-events-buffer (connection)
@ -405,7 +406,9 @@ remote endpoint (normal or error) are ignored and the function exits
returning CANCEL-ON-INPUT-RETVAL. If CANCEL-ON-INPUT is a function, it
is invoked with one argument, an integer identifying the canceled
request as specified in the JSONRPC 2.0 spec."
(let* ((tag (cl-gensym "jsonrpc-request-catch-tag")) id-and-timer
(let* ((tag (funcall (if (fboundp 'gensym) 'gensym 'cl-gensym)
"jsonrpc-request-catch-tag"))
id-and-timer
canceled
(throw-on-input nil)
(retval

View file

@ -325,7 +325,7 @@ The two cases that are handled are:
(cddr f))))
(if (and cl-closure-vars
(cl--expr-contains-any body cl-closure-vars))
(let* ((new (mapcar #'cl-gensym cl-closure-vars))
(let* ((new (mapcar #'gensym cl-closure-vars))
(sub (cl-pairlis cl-closure-vars new)) (decls nil))
(while (or (stringp (car body))
(eq (car-safe (car body)) 'interactive))
@ -372,7 +372,7 @@ lexical closures as in Common Lisp.
(cons (cons 'function #'cl--function-convert)
macroexpand-all-environment))))
(if (not (get (car (last cl-closure-vars)) 'used))
;; Turn (let ((foo (cl-gensym)))
;; Turn (let ((foo (gensym)))
;; (set foo <val>) ...(symbol-value foo)...)
;; into (let ((foo <val>)) ...(symbol-value 'foo)...).
;; This is good because it's more efficient but it only works with

View file

@ -60,7 +60,7 @@
;;; Code:
(require 'dired)
(require 'cl-lib) ; for cl-gensym
(require 'cl-lib)
;; CUSTOMIZATIONS
@ -176,7 +176,7 @@ this value can let another user see some of your images."
(format "%s%s-%s.jpg"
(thumbs-temp-dir)
thumbs-temp-prefix
(cl-gensym "T")))
(gensym "T")))
(defun thumbs-thumbsdir ()
"Return the current thumbnails directory (from `thumbs-thumbsdir').

View file

@ -881,7 +881,7 @@ Honor `eglot-strict-mode'."
"Function of args CL-LAMBDA-LIST for processing INTERFACE objects.
Honor `eglot-strict-mode'."
(declare (indent 1) (debug (sexp &rest form)))
(let ((e (cl-gensym "jsonrpc-lambda-elem")))
(let ((e (gensym "jsonrpc-lambda-elem")))
`(lambda (,e) (cl-block nil (eglot--dbind ,cl-lambda-list ,e ,@body)))))
(cl-defmacro eglot--dcase (obj &rest clauses)
@ -927,12 +927,12 @@ treated as in `eglot--dbind'."
(cl-defmacro eglot--when-live-buffer (buf &rest body)
"Check BUF live, then do BODY in it." (declare (indent 1) (debug t))
(let ((b (cl-gensym)))
(let ((b (gensym)))
`(let ((,b ,buf)) (if (buffer-live-p ,b) (with-current-buffer ,b ,@body)))))
(cl-defmacro eglot--when-buffer-window (buf &body body)
"Check BUF showing somewhere, then do BODY in it." (declare (indent 1) (debug t))
(let ((b (cl-gensym)))
(let ((b (gensym)))
`(let ((,b ,buf))
;;notice the exception when testing with `ert'
(when (or (get-buffer-window ,b) (ert-running-test))
@ -3142,7 +3142,7 @@ may be called multiple times (respecting the protocol of
(cl-defmacro eglot--collecting-xrefs ((collector) &rest body)
"Sort and handle xrefs collected with COLLECTOR in BODY."
(declare (indent 1) (debug (sexp &rest form)))
(let ((collected (cl-gensym "collected")))
(let ((collected (gensym "collected")))
`(unwind-protect
(let (,collected)
(cl-flet ((,collector (xref) (push xref ,collected)))
@ -4221,7 +4221,7 @@ at point. With prefix argument, prompt for ACTION-KIND."
collect (cl-loop
for (_token regexp emitter) in grammar
thereis (and (re-search-forward (concat "\\=" regexp) nil t)
(list (cl-gensym "state-") emitter (match-string 0)))
(list (gensym "state-") emitter (match-string 0)))
finally (error "Glob '%s' invalid at %s" (buffer-string) (point))))))
(cl-defun eglot--glob-fsm (states &key (exit 'eobp) noerror)

View file

@ -1247,7 +1247,7 @@ If it is running also stop it."
ARGS is a keyword-value plist passed to the backend along
with a report function."
(flymake-log :debug "Running backend %s" backend)
(let ((run-token (cl-gensym "backend-token")))
(let ((run-token (gensym "backend-token")))
(flymake--with-backend-state backend state
(setf (flymake--state-running state) run-token
(flymake--state-disabled state) nil

View file

@ -961,21 +961,14 @@ See Bug#57915."
:b 1)))
(ert-deftest cl-lib-test-gensym ()
;; Since the expansion of `should' calls `cl-gensym' and thus has a
;; side-effect on `cl--gensym-counter', we have to make sure all
;; macros in our test body are expanded before we rebind
;; `cl--gensym-counter' and run the body. Otherwise, the test would
;; fail if run interpreted.
(let ((body (byte-compile
'(lambda ()
(should (equal (symbol-name (cl-gensym)) "G0"))
(should (equal (symbol-name (cl-gensym)) "G1"))
(should (equal (symbol-name (cl-gensym)) "G2"))
(should (equal (symbol-name (cl-gensym "foo")) "foo3"))
(should (equal (symbol-name (cl-gensym "bar")) "bar4"))
(should (equal cl--gensym-counter 5))))))
(with-suppressed-warnings ((obsolete cl-gensym))
(let ((cl--gensym-counter 0))
(funcall body))))
(should (equal (symbol-name (cl-gensym)) "G0"))
(should (equal (symbol-name (cl-gensym)) "G1"))
(should (equal (symbol-name (cl-gensym)) "G2"))
(should (equal (symbol-name (cl-gensym "foo")) "foo3"))
(should (equal (symbol-name (cl-gensym "bar")) "bar4"))
(should (equal cl--gensym-counter 5)))))
(ert-deftest cl-the ()
(should (eql (cl-the integer 42) 42))

View file

@ -128,11 +128,11 @@
package-selected-packages
,@(if update-news
'(package-update-news-on-upload t)
(list (cl-gensym)))
(list (gensym)))
,@(if upload-base
'((package-test-archive-upload-base (make-temp-file "pkg-archive-base-" t))
(package-archive-upload-base package-test-archive-upload-base))
(list (cl-gensym)))) ;; Dummy value so `let' doesn't try to bind nil
(list (gensym)))) ;; Dummy value so `let' doesn't try to bind nil
(let ((buf (get-buffer "*Packages*")))
(when (buffer-live-p buf)
(kill-buffer buf)))

View file

@ -1236,7 +1236,7 @@ GUESSED-MAJOR-MODES-SYM are bound to the useful return values of
`eglot--guess-contact'. Unless the server program evaluates to
\"a-missing-executable.exe\", this macro will assume it exists."
(declare (indent 1) (debug t))
(let ((i-sym (cl-gensym)))
(let ((i-sym (gensym)))
`(dolist (,i-sym '(nil t))
(let ((,interactive-sym ,i-sym)
(buffer-file-name "_")

View file

@ -1050,7 +1050,7 @@ evaluation of BODY."
(ert-deftest elisp-shorthand-read-buffer ()
(let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
(let* ((gsym (downcase (symbol-name (gensym "sh-"))))
(shorthand-sname (format "s-%s" gsym))
(expected (intern (format "shorthand-longhand-%s" gsym))))
(cl-assert (not (intern-soft shorthand-sname)))
@ -1064,7 +1064,7 @@ evaluation of BODY."
(should (not (intern-soft shorthand-sname)))))
(ert-deftest elisp-shorthand-read-from-string ()
(let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
(let* ((gsym (downcase (symbol-name (gensym "sh-"))))
(shorthand-sname (format "s-%s" gsym))
(expected (intern (format "shorthand-longhand-%s" gsym))))
(cl-assert (not (intern-soft shorthand-sname)))