Subject: [PATCH] Mark cl-proclaim, cl-declaim, and cl-declare as obsolete

From: Stefan Kangas <[email-masked]>
Date: Wed, 19 Feb 2025 01:08:39 +0000

Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <[email-masked]> writes:

>> I really don't understand this code, I'm afraid.
>
> Don't worry: I don't think anybody does (I sure don't).
>
> It's code inherited from *many* years ago, where it approximated the
> desired semantics via approximate hacks (like delaying assignments
> until some package is loaded).
>
> We could try and go back to the CLHS doc to figure out what it "should"
> do, and then implement it better.  But seeing how little it's used,
> I doubt it's worth the trouble (my impression is that its intended
> semantics doesn't align very well with our implementation(s), so it
> would take work and/or ugly hacks to make it work "right").
>
>> So I'll commit the minimal change above, and hope that the rest of the
>> problem goes away when you have the time to look at it next :-)
>
> Looking at it doesn't make me very happy, so I don't have any plan to
> look at it.
>
> If you want to do me a favor you could try and mark it (both `proclaim`
> and `declaim`) as deprecated.

(This is a spin-off from Bug#63288.)

The code for the cl-lib declarations, i.e. (info "(cl) Declarations"),
is hacky, hard to maintain, and not well-understood by anyone.  It
doesn't seem to provide any benefits over using standard Emacs Lisp
facilities such as `declare`, `defvar`, and setting byte-compiler
variables.

The attached patch marks cl-proclaim, cl-declaim, and cl-declare as
obsolete.
From 0a2b5c851abff81ebcdefa2ff82976d7090f2e9b Mon Sep 17 00:00:00 2001
From: Stefan Kangas <[email-masked]>
Date: Tue, 18 Feb 2025 22:20:16 +0100
Subject: [PATCH] Mark cl-proclaim, cl-declaim, and cl-declare as obsolete

* lisp/emacs-lisp/cl-lib.el (cl-proclaim, cl-declaim):
* lisp/emacs-lisp/cl-macs.el (cl-declare): Mark as obsolete.
* doc/misc/cl.texi (Declarations): Don't document above obsoleted
functions and macros.

Ref: https://debbugs.gnu.org/cgi/bugreport.cgi?bug=63288#83
---
 doc/misc/cl.texi           | 152 +------------------------------------
 etc/NEWS                   |  10 +++
 lisp/emacs-lisp/cl-lib.el  |   2 +
 lisp/emacs-lisp/cl-macs.el |   1 +
 4 files changed, 16 insertions(+), 149 deletions(-)

diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index da73aeb6387..e1e67e2c0e7 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -60,7 +60,7 @@ Top
 * Predicates::           Type predicates and equality predicates.
 * Control Structure::    Assignment, conditionals, blocks, looping.
 * Macros::               Destructuring, compiler macros.
-* Declarations::         @code{cl-proclaim}, @code{cl-declare}, etc.
+* Declarations::         @code{cl-the}.
 * Symbols::              Property lists, creating symbols.
 * Numbers::              Predicates, functions, random numbers.
 * Sequences::            Mapping, functions, searching, sorting.
@@ -2745,46 +2745,12 @@ Declarations
 mechanism that allows you to give the compiler special hints
 about the types of data that will be stored in particular variables,
 and about the ways those variables and functions will be used.  This
-package defines versions of all the Common Lisp declaration forms:
-@code{declare}, @code{locally}, @code{proclaim}, @code{declaim},
-and @code{the}.
+package defines a versions of only one Common Lisp declaration forms:
+@code{the}.
 
 Most of the Common Lisp declarations are not currently useful in Emacs
 Lisp.  For example, the byte-code system provides little
 opportunity to benefit from type information.
-@ignore
-and @code{special} declarations are redundant in a fully
-dynamically-scoped Lisp.
-@end ignore
-A few declarations are meaningful when byte compiler optimizations
-are enabled, as they are by the default.  Otherwise these
-declarations will effectively be ignored.
-
-@defun cl-proclaim decl-spec
-This function records a ``global'' declaration specified by
-@var{decl-spec}.  Since @code{cl-proclaim} is a function, @var{decl-spec}
-is evaluated and thus should normally be quoted.
-@end defun
-
-@defmac cl-declaim decl-specs@dots{}
-This macro is like @code{cl-proclaim}, except that it takes any number
-of @var{decl-spec} arguments, and the arguments are unevaluated and
-unquoted.  The @code{cl-declaim} macro also puts @code{(cl-eval-when
-(compile load eval) @dots{})} around the declarations so that they will
-be registered at compile-time as well as at run-time.  (This is vital,
-since normally the declarations are meant to influence the way the
-compiler treats the rest of the file that contains the @code{cl-declaim}
-form.)
-@end defmac
-
-@defmac cl-declare decl-specs@dots{}
-This macro is used to make declarations within functions and other
-code.  Common Lisp allows declarations in various locations, generally
-at the beginning of any of the many ``implicit @code{progn}s''
-throughout Lisp syntax, such as function bodies, @code{let} bodies,
-etc.  Currently the only declaration understood by @code{cl-declare}
-is @code{special}.
-@end defmac
 
 @defmac cl-the type form
 @code{cl-the} returns the value of @code{form}, first checking (if
@@ -2801,118 +2767,6 @@ Declarations
 to @code{(mapcar 'car foo)}.
 @end defmac
 
-Each @var{decl-spec} in a @code{cl-proclaim}, @code{cl-declaim}, or
-@code{cl-declare} should be a list beginning with a symbol that says
-what kind of declaration it is.  This package currently understands
-@code{special}, @code{inline}, @code{notinline}, @code{optimize},
-and @code{warn} declarations.  (The @code{warn} declaration is an
-extension of standard Common Lisp.)  Other Common Lisp declarations,
-such as @code{type} and @code{ftype}, are silently ignored.
-
-@table @code
-@item special
-@c FIXME ?
-Since all variables in Emacs Lisp are ``special'' (in the Common
-Lisp sense), @code{special} declarations are only advisory.  They
-simply tell the byte compiler that the specified
-variables are intentionally being referred to without being
-bound in the body of the function.  The compiler normally emits
-warnings for such references, since they could be typographical
-errors for references to local variables.
-
-The declaration @code{(cl-declare (special @var{var1} @var{var2}))} is
-equivalent to @code{(defvar @var{var1}) (defvar @var{var2})}.
-
-In top-level contexts, it is generally better to write
-@code{(defvar @var{var})} than @code{(cl-declaim (special @var{var}))},
-since @code{defvar} makes your intentions clearer.
-
-@item inline
-The @code{inline} @var{decl-spec} lists one or more functions
-whose bodies should be expanded ``in-line'' into calling functions
-whenever the compiler is able to arrange for it.  For example,
-the function @code{cl-acons} is declared @code{inline}
-by this package so that the form @code{(cl-acons @var{key} @var{value}
-@var{alist})} will
-expand directly into @code{(cons (cons @var{key} @var{value}) @var{alist})}
-when it is called in user functions, so as to save function calls.
-
-The following declarations are all equivalent.  Note that the
-@code{defsubst} form is a convenient way to define a function
-and declare it inline all at once.
-
-@example
-(cl-declaim (inline foo bar))
-(cl-eval-when (compile load eval)
-  (cl-proclaim '(inline foo bar)))
-(defsubst foo (@dots{}) @dots{})       ; instead of defun
-@end example
-
-@strong{Please note:}  this declaration remains in effect after the
-containing source file is done.  It is correct to use it to
-request that a function you have defined should be inlined,
-but it is impolite to use it to request inlining of an external
-function.
-
-In Common Lisp, it is possible to use @code{(declare (inline @dots{}))}
-before a particular call to a function to cause just that call to
-be inlined; the current byte compilers provide no way to implement
-this, so @code{(cl-declare (inline @dots{}))} is currently ignored by
-this package.
-
-@item notinline
-The @code{notinline} declaration lists functions which should
-not be inlined after all; it cancels a previous @code{inline}
-declaration.
-
-@item optimize
-This declaration controls how much optimization is performed by
-the compiler.
-
-The word @code{optimize} is followed by any number of lists like
-@code{(speed 3)} or @code{(safety 2)}.  Common Lisp defines several
-optimization ``qualities''; this package ignores all but @code{speed}
-and @code{safety}.  The value of a quality should be an integer from
-0 to 3, with 0 meaning ``unimportant'' and 3 meaning ``very important''.
-The default level for both qualities is 1.
-
-In this package, the @code{speed} quality is tied to the @code{byte-optimize}
-flag, which is set to @code{nil} for @code{(speed 0)} and to
-@code{t} for higher settings; and the @code{safety} quality is
-tied to the @code{byte-compile-delete-errors} flag, which is
-set to @code{nil} for @code{(safety 3)} and to @code{t} for all
-lower settings.  (The latter flag controls whether the compiler
-is allowed to optimize out code whose only side-effect could
-be to signal an error, e.g., rewriting @code{(progn foo bar)} to
-@code{bar} when it is not known whether @code{foo} will be bound
-at run-time.)
-
-Note that even compiling with @code{(safety 0)}, the Emacs
-byte-code system provides sufficient checking to prevent real
-harm from being done.  For example, barring serious bugs in
-Emacs itself, Emacs will not crash with a segmentation fault
-just because of an error in a fully-optimized Lisp program.
-
-The @code{optimize} declaration is normally used in a top-level
-@code{cl-proclaim} or @code{cl-declaim} in a file; Common Lisp allows
-it to be used with @code{declare} to set the level of optimization
-locally for a given form, but this will not work correctly with the
-current byte-compiler.  (The @code{cl-declare}
-will set the new optimization level, but that level will not
-automatically be unset after the enclosing form is done.)
-
-@item warn
-This declaration controls what sorts of warnings are generated
-by the byte compiler.  The word @code{warn} is followed by any
-number of ``warning qualities'', similar in form to optimization
-qualities.  The currently supported warning types are
-@code{redefine}, @code{callargs}, @code{unresolved}, and
-@code{free-vars}; in the current system, a value of 0 will
-disable these warnings and any higher value will enable them.
-See the documentation of the variable @code{byte-compile-warnings}
-for more details.
-@end table
-
 @node Symbols
 @chapter Symbols
 
diff --git a/etc/NEWS b/etc/NEWS
index bd7ee0f8b13..f1347a27032 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -503,6 +503,16 @@ Such bindings make it possible to compute which function to bind to FUNC.
 *** 'cl-locally' is now obsolete.
 It is an alias for the 'progn' special-form.
 
++++
+*** 'cl-proclaim' and 'cl-declaim' are now obsolete.
+These rarely used macros are hard to maintain due to relying on hacks,
+and don't provide more than marginal benefits over standard Emacs Lisp
+facilities (such as 'declare').
+
++++
+*** 'cl-declare' is now obsolete.
+Use a regular 'defvar' instead.
+
 ** Whitespace
 
 ---
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 4a83e9d6a7c..9cbd9bf2f5e 100644
--- a/lisp/emacs-lisp/cl-lib.el
+++ b/lisp/emacs-lisp/cl-lib.el
@@ -253,6 +253,7 @@ cl--proclaims-deferred
 
 (defun cl-proclaim (spec)
   "Record a global declaration specified by SPEC."
+  (declare (obsolete nil "31.1"))
   (if (fboundp 'cl--do-proclaim) (cl--do-proclaim spec t)
     (push spec cl--proclaims-deferred))
   nil)
@@ -261,6 +262,7 @@ cl-declaim
   "Like `cl-proclaim', but takes any number of unevaluated, unquoted arguments.
 Puts `(cl-eval-when (compile load eval) ...)' around the declarations
 so that they are registered at compile-time as well as run-time."
+  (declare (obsolete nil "31.1"))
   (let ((body (mapcar (lambda (x) `(cl-proclaim ',x)) specs)))
     (if (macroexp-compiling-p) `(cl-eval-when (compile load eval) ,@body)
       `(progn ,@body))))           ; Avoid loading cl-macs.el for cl-eval-when.
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 2712dae0d5e..31418d9eb91 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2728,6 +2728,7 @@ cl-declare
 
 will turn off byte-compile warnings in the function.
 See Info node `(cl)Declarations' for details."
+  (declare (obsolete nil "31.1"))
   (if (macroexp-compiling-p)
       (while specs
 	(if (listp cl--declare-stack) (push (car specs) cl--declare-stack))
-- 
2.48.1