diff --git a/doc/lispref/numbers.texi b/doc/lispref/numbers.texi index 17fa1e05fee..29105959ecd 100644 --- a/doc/lispref/numbers.texi +++ b/doc/lispref/numbers.texi @@ -668,8 +668,8 @@ foo @result{} 4 @end example -If you want to increment the variable, you must use @code{setq}, -like this: +If you want to increment the variable, you must use @code{setq} (or +@code{incf}), like this: @example (setq foo (1+ foo)) @@ -681,6 +681,21 @@ like this: This function returns @var{number-or-marker} minus 1. @end defun +@defmac incf place &optional delta +This macro increments the number stored in @var{place} by one, or +by @var{delta} if specified. The incremented value is returned. + +@var{place} can be a symbol or a generalized variable, @xref{Generalized +Variables}. For example, @code{(incf i)} is equivalent to +@code{(setq i (1+ i))}, and @code{(incf (car x) 2)} is equivalent to +@code{(setcar x (+ (car x) 2))}. +@end defmac + +@defmac decf place &optional delta +This macro decrements the number stored in @var{place} by one, or +by @var{delta} if specified. The decremented value is returned. +@end defmac + @defun + &rest numbers-or-markers This function adds its arguments together. When given no arguments, @code{+} returns 0. diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 998a74d067a..46027edb041 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -3130,7 +3130,7 @@ If the multisession variable is synchronized, setting it may update the value first. For instance: @lisp -(cl-incf (multisession-value foo-bar)) +(incf (multisession-value foo-bar)) @end lisp This first checks whether the value has changed in a different diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi index f95900a085e..8fb308e64a5 100644 --- a/doc/misc/cl.texi +++ b/doc/misc/cl.texi @@ -168,9 +168,6 @@ and information about the package. This file is relatively compact. @item cl-extra.el This file contains the larger, more complex or unusual functions. -It is kept separate so that packages which only want to use Common -Lisp fundamentals like the @code{cl-incf} function won't need to pay -the overhead of loading the more advanced functions. @item cl-seq.el This file contains most of the advanced functions for operating @@ -197,8 +194,8 @@ this package prior to Emacs 24.3. Nowadays, it is replaced by but use different function names (in fact, @file{cl.el} mainly just defines aliases to the @file{cl-lib.el} definitions). Where @file{cl-lib.el} defines a function called, for example, -@code{cl-incf}, @file{cl.el} uses the same name but without the -@samp{cl-} prefix, e.g., @code{incf} in this example. There are a few +@code{cl-first}, @file{cl.el} uses the same name but without the +@samp{cl-} prefix, e.g., @code{first} in this example. There are a few exceptions to this. First, functions such as @code{cl-defun} where the unprefixed version was already used for a standard Emacs Lisp function. In such cases, the @file{cl.el} version adds a @samp{*} @@ -1028,7 +1025,7 @@ generalized variables. @menu * Setf Extensions:: Additional @code{setf} places. -* Modify Macros:: @code{cl-incf}, @code{cl-rotatef}, @code{cl-letf}, @code{cl-callf}, etc. +* Modify Macros:: @code{cl-rotatef}, @code{cl-letf}, @code{cl-callf}, etc. @end menu @node Setf Extensions @@ -1085,52 +1082,6 @@ Specifically, all subforms are evaluated from left to right, then all the assignments are done (in an undefined order). @end defmac -@defmac cl-incf place &optional x -This macro increments the number stored in @var{place} by one, or -by @var{x} if specified. The incremented value is returned. For -example, @code{(cl-incf i)} is equivalent to @code{(setq i (1+ i))}, and -@code{(cl-incf (car x) 2)} is equivalent to @code{(setcar x (+ (car x) 2))}. - -As with @code{setf}, care is taken to preserve the ``apparent'' order -of evaluation. For example, - -@example -(cl-incf (aref vec (cl-incf i))) -@end example - -@noindent -appears to increment @code{i} once, then increment the element of -@code{vec} addressed by @code{i}; this is indeed exactly what it -does, which means the above form is @emph{not} equivalent to the -``obvious'' expansion, - -@example -(setf (aref vec (cl-incf i)) - (1+ (aref vec (cl-incf i)))) ; wrong! -@end example - -@noindent -but rather to something more like - -@example -(let ((temp (cl-incf i))) - (setf (aref vec temp) (1+ (aref vec temp)))) -@end example - -@noindent -Again, all of this is taken care of automatically by @code{cl-incf} and -the other generalized-variable macros. - -As a more Emacs-specific example of @code{cl-incf}, the expression -@code{(cl-incf (point) @var{n})} is essentially equivalent to -@code{(forward-char @var{n})}. -@end defmac - -@defmac cl-decf place &optional x -This macro decrements the number stored in @var{place} by one, or -by @var{x} if specified. -@end defmac - @defmac cl-pushnew x place @t{&key :test :test-not :key} This macro inserts @var{x} at the front of the list stored in @var{place}, but only if @var{x} isn't present in the list already. @@ -1243,8 +1194,8 @@ It does the bindings in sequential rather than parallel order. This is the ``generic'' modify macro. It calls @var{function}, which should be an unquoted function name, macro name, or lambda. It passes @var{place} and @var{args} as arguments, and assigns the -result back to @var{place}. For example, @code{(cl-incf @var{place} -@var{n})} is the same as @code{(cl-callf + @var{place} @var{n})}. +result back to @var{place}. For example, @code{(incf @var{place} +@var{n})} could be implemented as @code{(cl-callf + @var{place} @var{n})}. Some more examples: @example @@ -1264,7 +1215,7 @@ equivalent to @code{(cl-callf2 cons @var{x} @var{place})}. @end defmac The @code{cl-callf} and @code{cl-callf2} macros serve as building -blocks for other macros like @code{cl-incf}, and @code{cl-pushnew}. +blocks for other macros like @code{cl-pushnew}. The @code{cl-letf} and @code{cl-letf*} macros are used in the processing of symbol macros; @pxref{Macro Bindings}. @@ -1401,7 +1352,7 @@ replaced by @var{expansion}. @example (setq bar '(5 . 9)) (cl-symbol-macrolet ((foo (car bar))) - (cl-incf foo)) + (incf foo)) bar @result{} (6 . 9) @end example @@ -1426,7 +1377,7 @@ expansion of another macro: body)))) (setq mylist '(1 2 3 4)) -(my-dolist (x mylist) (cl-incf x)) +(my-dolist (x mylist) (incf x)) mylist @result{} (2 3 4 5) @end example @@ -1440,14 +1391,14 @@ shown here expands to @example (cl-loop for G1234 on mylist do (cl-symbol-macrolet ((x (car G1234))) - (cl-incf x))) + (incf x))) @end example @noindent which in turn expands to @example -(cl-loop for G1234 on mylist do (cl-incf (car G1234))) +(cl-loop for G1234 on mylist do (incf (car G1234))) @end example @xref{Loop Facility}, for a description of the @code{cl-loop} macro. @@ -1999,7 +1950,7 @@ a @code{setf}-able ``reference'' onto the elements of the list rather than just a temporary variable. For example, @example -(cl-loop for x in-ref my-list do (cl-incf x)) +(cl-loop for x in-ref my-list do (incf x)) @end example @noindent @@ -2940,7 +2891,7 @@ The @code{get} and @code{cl-get} functions are also @code{setf}-able. The fact that @code{default} is ignored can sometimes be useful: @example -(cl-incf (cl-get 'foo 'usage-count 0)) +(incf (cl-get 'foo 'usage-count 0)) @end example Here, symbol @code{foo}'s @code{usage-count} property is incremented @@ -4051,7 +4002,7 @@ calling @code{(person-first-name @var{p})}, @code{(person-age slots by using @code{setf} on any of these place forms, for example: @example -(cl-incf (person-age birthday-boy)) +(incf (person-age birthday-boy)) @end example You can create a new @code{person} by calling @code{make-person}, @@ -4459,29 +4410,14 @@ user to modify @var{place}. Many of the advanced features of this package, such as @code{cl-defun}, @code{cl-loop}, etc., are implemented as Lisp macros. In byte-compiled code, these complex notations will be expanded into -equivalent Lisp code which is simple and efficient. For example, -the form - -@example -(cl-incf i n) -@end example - -@noindent -is expanded at compile-time to the Lisp form - -@example -(setq i (+ i n)) -@end example - -@noindent -which is the most efficient way of doing this operation -in Lisp. Thus, there is no performance penalty for using the more -readable @code{cl-incf} form in your compiled code. +equivalent Lisp code which is simple and efficient. Thus, there is no +performance penalty for using the more readable form in your compiled +code. @emph{Interpreted} code, on the other hand, must expand these macros every time they are executed. For this reason it is strongly recommended that code making heavy use of macros be compiled. -A loop using @code{cl-incf} a hundred times will execute considerably +A loop using @code{cl-first} a hundred times will execute considerably faster if compiled, and will also garbage-collect less because the macro expansion will not have to be generated, used, and thrown away a hundred times. @@ -4907,7 +4843,7 @@ call to @code{make-adder} itself. @example (defun make-counter () (lexical-let ((n 0)) - (cl-function (lambda (&optional (m 1)) (cl-incf n m))))) + (cl-function (lambda (&optional (m 1)) (incf n m))))) (setq count-1 (make-counter)) (funcall count-1 3) @result{} 3 @@ -5052,7 +4988,7 @@ In Emacs, these are obsolete, replaced by various features of @defmac define-modify-macro name arglist function [doc-string] This macro defines a ``read-modify-write'' macro similar to -@code{cl-incf} and @code{cl-decf}. You can replace this macro +@code{incf} and @code{decf}. You can replace this macro with @code{gv-letplace}. The macro @var{name} is defined to take a @var{place} argument @@ -5180,8 +5116,8 @@ For example, the simple form of @code{defsetf} is shorthand for The Lisp form that is returned can access the arguments from @var{arglist} and @var{store-var} in an unrestricted fashion; -macros like @code{cl-incf} that invoke this -setf-method will insert temporary variables as needed to make +macros that invoke this +setf-method should insert temporary variables as needed to make sure the apparent order of evaluation is preserved. Another standard example: @@ -5245,11 +5181,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 -@c FIXME I don't think this is true anymore. -by @code{cl-gensym}. Macros like @code{cl-incf} that -use this setf-method will optimize away most temporaries that -turn out to be unnecessary, so there is little reason for the -setf-method itself to optimize. +by @code{cl-gensym}. @end defmac @node GNU Free Documentation License diff --git a/etc/NEWS b/etc/NEWS index a03ffe91ab9..0c54fc2c4a9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -491,12 +491,18 @@ Emacs 25.1), and gnudoit (obsolete since Emacs 25.1). ** CL-Lib +++ -*** Some cl-lib functions are now built-in. -The functions 'cl-plusp', 'cl-minusp', 'cl-oddp', and 'cl-evenp', have -been added to Emacs Lisp, and are thus now aliases for the built-in -functions 'plusp', 'minusp', 'oddp' and 'evenp'. The old names are -considered deprecated, and will be marked as obsolete in some future -release. +*** Some cl-lib functions and macros are now built-in. +These functions or macros have been added to Emacs Lisp, and the old +names are now aliases for the built-in equivalents: + - 'cl-incf' renamed to 'incf' + - 'cl-decf' renamed to 'decf' + - 'cl-oddp' renamed to 'oddp' + - 'cl-evenp' renamed to 'evenp' + - 'cl-plusp' renamed to 'plusp' + - 'cl-minusp' renamed to 'minusp' + +The old names are considered deprecated, and will be marked as obsolete +in some future release. +++ *** 'cl-labels' now also accepts '(FUNC EXP)' bindings, like 'cl-flet'. @@ -1356,6 +1362,11 @@ change it globally with: (set-default-toplevel-value 'lexical-binding t) ++++ +*** New functions 'incf' and 'decf'. +They increment or decrement the value stored in a variable (a symbol), +or in a generalized variable. + +++ ** New functions 'plusp' and 'minusp'. They return non-nil if a number is positive or negative, respectively, diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index 2a952b57646..42460fc2c9f 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el @@ -105,29 +105,27 @@ a future Emacs interpreter will be able to use it.") ;; can safely be used in init files. ;;;###autoload -(defmacro cl-incf (place &optional x) +(defalias 'cl-incf #'incf "Increment PLACE by X (1 by default). PLACE may be a symbol, or any generalized variable allowed by `setf'. The return value is the incremented value of PLACE. If X is specified, it should be an expression that should -evaluate to a number." - (declare (debug (place &optional form))) - (if (symbolp place) - (list 'setq place (if x (list '+ place x) (list '1+ place))) - (list 'cl-callf '+ place (or x 1)))) +evaluate to a number. -(defmacro cl-decf (place &optional x) +This macro is considered deprecated in favor of the built-in macro +`incf' that was added in Emacs 31.1.") + +(defalias 'cl-decf #'decf "Decrement PLACE by X (1 by default). PLACE may be a symbol, or any generalized variable allowed by `setf'. The return value is the decremented value of PLACE. If X is specified, it should be an expression that should -evaluate to a number." - (declare (debug cl-incf)) - (if (symbolp place) - (list 'setq place (if x (list '- place x) (list '1- place))) - (list 'cl-callf '- place (or x 1)))) +evaluate to a number. + +This macro is considered deprecated in favor of the built-in macro +`decf' that was added in Emacs 31.1.") (defmacro cl-pushnew (x place &rest keys) "Add X to the list stored in PLACE unless X is already in the list. diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el index dcbdf6942f7..d9ba786aa7d 100644 --- a/lisp/emacs-lisp/gv.el +++ b/lisp/emacs-lisp/gv.el @@ -315,17 +315,29 @@ The return value is the last VAL in the list. ;; `(if (member ,v ,getter) nil ;; ,(funcall setter `(cons ,v ,getter)))))) -;; (defmacro gv-inc! (place &optional val) -;; "Increment PLACE by VAL (default to 1)." -;; (declare (debug (gv-place &optional form))) -;; (gv-letplace (getter setter) place -;; (funcall setter `(+ ,getter ,(or val 1))))) +;;;###autoload +(defmacro incf (place &optional delta) + "Increment PLACE by DELTA (default to 1). -;; (defmacro gv-dec! (place &optional val) -;; "Decrement PLACE by VAL (default to 1)." -;; (declare (debug (gv-place &optional form))) -;; (gv-letplace (getter setter) place -;; (funcall setter `(- ,getter ,(or val 1))))) +The DELTA is first added to PLACE, and then stored in PLACE. +Return the incremented value of PLACE. + +See also `decf'." + (declare (debug (gv-place &optional form))) + (gv-letplace (getter setter) place + (funcall setter `(+ ,getter ,(or delta 1))))) + +;;;###autoload +(defmacro decf (place &optional delta) + "Decrement PLACE by DELTA (default to 1). + +The DELTA is first subtracted from PLACE, and then stored in PLACE. +Return the decremented value of PLACE. + +See also `incf'." + (declare (debug (gv-place &optional form))) + (gv-letplace (getter setter) place + (funcall setter `(- ,getter ,(or delta 1))))) ;; For Edebug, the idea is to let Edebug instrument gv-places just like it does ;; for normal expressions, and then give it a gv-expander to DTRT. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 23b9b582a9a..77a4ec4f21c 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -1375,9 +1375,17 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'), :eval (mod 10 6) :eval (mod 10.5 6)) (1+ - :eval (1+ 2)) + :eval (1+ 2) + :eval (let ((x 2)) (1+ x) x)) (1- - :eval (1- 4)) + :eval (1- 4) + :eval (let ((x 4)) (1- x) x)) + (incf + :eval (let ((x 2)) (incf x) x) + :eval (let ((x 2)) (incf x 2) x)) + (decf + :eval (let ((x 4)) (decf x) x) + :eval (let ((x 4)) (decf x 2)) x) "Predicates" (= :args (number &rest numbers) diff --git a/lisp/obsolete/cl.el b/lisp/obsolete/cl.el index 5baa155c592..5fbfbb7899e 100644 --- a/lisp/obsolete/cl.el +++ b/lisp/obsolete/cl.el @@ -282,8 +282,6 @@ values-list values pushnew - decf - incf )) (let ((new (if (consp fun) (prog1 (cdr fun) (setq fun (car fun))) (intern (format "cl-%s" fun))))) diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el b/test/lisp/emacs-lisp/cl-lib-tests.el index 376566958a0..d7c38b73432 100644 --- a/test/lisp/emacs-lisp/cl-lib-tests.el +++ b/test/lisp/emacs-lisp/cl-lib-tests.el @@ -63,42 +63,6 @@ (should (equal (cl-multiple-value-list nil) nil)) (should (equal (cl-multiple-value-list (list 1 2 3)) '(1 2 3)))) -(defvar cl-lib-test--special 0) - -(ert-deftest cl-lib-test-incf () - (setq cl-lib-test--special 0) - (should (= (cl-incf cl-lib-test--special) 1)) - (should (= cl-lib-test--special 1)) - (should (= (cl-incf cl-lib-test--special 9) 10)) - (should (= cl-lib-test--special 10)) - (let ((var 0)) - (should (= (cl-incf var) 1)) - (should (= var 1)) - (should (= (cl-incf var 9) 10)) - (should (= var 10))) - (let ((alist)) - (should (= (cl-incf (alist-get 'a alist 0)) 1)) - (should (= (alist-get 'a alist 0) 1)) - (should (= (cl-incf (alist-get 'a alist 0) 9) 10)) - (should (= (alist-get 'a alist 0) 10)))) - -(ert-deftest cl-lib-test-decf () - (setq cl-lib-test--special 0) - (should (= (cl-decf cl-lib-test--special) -1)) - (should (= cl-lib-test--special -1)) - (should (= (cl-decf cl-lib-test--special 9) -10)) - (should (= cl-lib-test--special -10)) - (let ((var 1)) - (should (= (cl-decf var) 0)) - (should (= var 0)) - (should (= (cl-decf var 10) -10)) - (should (= var -10))) - (let ((alist)) - (should (= (cl-decf (alist-get 'a alist 0)) -1)) - (should (= (alist-get 'a alist 0) -1)) - (should (= (cl-decf (alist-get 'a alist 0) 9) -10)) - (should (= (alist-get 'a alist 0) -10)))) - (ert-deftest cl-digit-char-p () (should (eql 3 (cl-digit-char-p ?3))) (should (eql 10 (cl-digit-char-p ?a 11))) diff --git a/test/lisp/emacs-lisp/gv-tests.el b/test/lisp/emacs-lisp/gv-tests.el index 5ea386e0b5d..892af4bfab1 100644 --- a/test/lisp/emacs-lisp/gv-tests.el +++ b/test/lisp/emacs-lisp/gv-tests.el @@ -163,6 +163,42 @@ its getter (Bug#41853)." (eval-buffer)))) (should (equal (get 'gv-setter-edebug 'gv-setter-edebug-prop) '(123)))) +(defvar gv-test--special 0) + +(ert-deftest gv-incf () + (setq gv-test--special 0) + (should (= (incf gv-test--special) 1)) + (should (= gv-test--special 1)) + (should (= (incf gv-test--special 9) 10)) + (should (= gv-test--special 10)) + (let ((var 0)) + (should (= (incf var) 1)) + (should (= var 1)) + (should (= (incf var 9) 10)) + (should (= var 10))) + (let ((alist)) + (should (= (incf (alist-get 'a alist 0)) 1)) + (should (= (alist-get 'a alist 0) 1)) + (should (= (incf (alist-get 'a alist 0) 9) 10)) + (should (= (alist-get 'a alist 0) 10)))) + +(ert-deftest gv-decf () + (setq gv-test--special 0) + (should (= (decf gv-test--special) -1)) + (should (= gv-test--special -1)) + (should (= (decf gv-test--special 9) -10)) + (should (= gv-test--special -10)) + (let ((var 1)) + (should (= (decf var) 0)) + (should (= var 0)) + (should (= (decf var 10) -10)) + (should (= var -10))) + (let ((alist)) + (should (= (decf (alist-get 'a alist 0)) -1)) + (should (= (alist-get 'a alist 0) -1)) + (should (= (decf (alist-get 'a alist 0) 9) -10)) + (should (= (alist-get 'a alist 0) -10)))) + (ert-deftest gv-plist-get () ;; Simple `setf' usage for `plist-get'. (let ((target (list :a "a" :b "b" :c "c")))