aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/misc/cl.texi49
-rw-r--r--etc/NEWS10
-rw-r--r--lisp/emacs-lisp/cl-macs.el44
-rw-r--r--test/lisp/emacs-lisp/cl-macs-tests.el15
4 files changed, 118 insertions, 0 deletions
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index e51e245c736..7219494391b 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -4066,6 +4066,55 @@ A documentation string describing the slot.
4066 4066
4067Other slot options are currently ignored. 4067Other slot options are currently ignored.
4068 4068
4069@defmac cl-with-accessors name bindings body@dot{}
4070You can use @code{cl-with-accessors} to lexically define symbols as
4071expressions calling the given accessor functions on a single instance of
4072a structure or class defined by @code{cl-defstruct} or @code{defclass}
4073(@pxref{eieio}). This can simplify code that repeatedly accesses slots.
4074With it, you can use @code{setf} and @code{setq} on the symbols like
4075normal variables, modifying the values in the structure. Unlike the
4076macro @code{with-slots} (@pxref{Accessing Slots,,,eieio,EIEIO}), because
4077the symbol expands to a function call, @code{cl-with-accessors} can be
4078used with any generalized variable that can take a single argument, such
4079as @code{cl-first} and @code{cl-rest}.
4080@end defmac
4081
4082@example
4083;; Using accessors with long, clear names without the macro:
4084(defun internal-normalization (person)
4085 "Correct the values of the slots in PERSON to be as expected."
4086 ;; Check the values of the structure:
4087 (when (equal (person-optional-secondary-data person) "")
4088 (setf (person-optional-secondary-data person) nil))
4089 (when (null (person-access-settings person))
4090 (setf (person-access-settings person) 'default))
4091 (when (< (long-accessor-name-that-can-become-unreadable-when-repeated
4092 person)
4093 9)
4094 (cl-incf (long-accessor-name-that-can-become-unreadable-when-repeated
4095 person)
4096 100))
4097 ;; And so on before returning the structure:
4098 person)
4099
4100;; Using accessors with long, clear names with the macro:
4101(defun internal-normalization (person)
4102 "Correct the values of the slots in PERSON to be as expected."
4103 (cl-with-accessors ((secondary-data person-optional-secondary-data)
4104 (access-settings person-access-settings)
4105 (short-name person-much-longer-accessor-name))
4106 person
4107 ;; Check the values of the structure:
4108 (when (equal secondary-data "")
4109 (setf secondary-data nil))
4110 (when (null access-settings)
4111 (setf access-settings 'default))
4112 (when (< short-name 9)
4113 (cl-incf short-name 100))
4114 ;; And so on before returning the structure:
4115 person))
4116@end example
4117
4069For obscure historical reasons, structure options take a different 4118For obscure historical reasons, structure options take a different
4070form than slot options. A structure option is either a keyword 4119form than slot options. A structure option is either a keyword
4071symbol, or a list beginning with a keyword symbol possibly followed 4120symbol, or a list beginning with a keyword symbol possibly followed
diff --git a/etc/NEWS b/etc/NEWS
index afa45c5ca0d..8c65b195b1a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1611,6 +1611,16 @@ New faces have been added to 'icomplete-vertical-mode':
1611- 'icomplete-vertical-unselected-prefix-indicator-face' controls the 1611- 'icomplete-vertical-unselected-prefix-indicator-face' controls the
1612 appearance of unselected candidate prefixes. 1612 appearance of unselected candidate prefixes.
1613 1613
1614** CL-Lib
1615
1616+++
1617*** New macro 'cl-with-accessors'.
1618This macro is similar to 'with-slots', but uses accessor functions
1619instead of slot names. It is useful when slots' accessor functions are
1620used repeatedly, such as reading from a slot and then writing to that
1621slot. Symbol macros are created for the accessor functions using
1622'cl-symbol-macrolet', so that they can be used with 'setq' and 'setf'.
1623
1614** Miscellaneous 1624** Miscellaneous
1615 1625
1616--- 1626---
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 960f2e6742b..cc1c6a6a5ad 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2576,6 +2576,50 @@ See also `macroexp-let2'."
2576 collect `(,(car name) ,gensym)) 2576 collect `(,(car name) ,gensym))
2577 ,@body))))) 2577 ,@body)))))
2578 2578
2579;;;###autoload
2580(defmacro cl-with-accessors (bindings instance &rest body)
2581 "Use BINDINGS as function calls on INSTANCE inside BODY.
2582
2583This macro helps when writing code that makes repeated use of the
2584accessor functions of a structure or object instance, such as those
2585created by `cl-defstruct' and `defclass'.
2586
2587BINDINGS is a list of (NAME ACCESSOR) pairs. Inside BODY, NAME is
2588treated as the function call (ACCESSOR INSTANCE) using
2589`cl-symbol-macrolet'. NAME can be used with `setf' and `setq' as a
2590generalized variable. Because of how the accessor is used,
2591`cl-with-accessors' can be used with any generalized variable that can
2592take a single argument, such as `car' and `cdr'.
2593
2594See also the macro `with-slots' described in the Info
2595node `(eieio)Accessing Slots', which is similar, but uses slot names
2596instead of accessor functions.
2597
2598\(fn ((NAME ACCESSOR) ...) INSTANCE &rest BODY)"
2599 (declare (debug [(&rest (symbolp symbolp)) form body])
2600 (indent 2))
2601 (cond ((null body)
2602 (macroexp-warn-and-return "`cl-with-accessors' used with empty body"
2603 nil 'empty-body))
2604 ((null bindings)
2605 (macroexp-warn-and-return "`cl-with-accessors' used without accessors"
2606 (macroexp-progn body)
2607 'suspicious))
2608 (t
2609 (cl-once-only (instance)
2610 (let ((symbol-macros))
2611 (dolist (b bindings)
2612 (pcase b
2613 (`(,(and (pred symbolp) var)
2614 ,(and (pred symbolp) accessor))
2615 (push `(,var (,accessor ,instance))
2616 symbol-macros))
2617 (_
2618 (error "Malformed `cl-with-accessors' binding: %S" b))))
2619 `(cl-symbol-macrolet
2620 ,symbol-macros
2621 ,@body))))))
2622
2579;;; Multiple values. 2623;;; Multiple values.
2580 2624
2581;;;###autoload 2625;;;###autoload
diff --git a/test/lisp/emacs-lisp/cl-macs-tests.el b/test/lisp/emacs-lisp/cl-macs-tests.el
index b4b939d3d31..ed6b1c2e4d4 100644
--- a/test/lisp/emacs-lisp/cl-macs-tests.el
+++ b/test/lisp/emacs-lisp/cl-macs-tests.el
@@ -541,6 +541,21 @@ collection clause."
541 (should (mystruct-p (cl-lib--con-1))) 541 (should (mystruct-p (cl-lib--con-1)))
542 (should (mystruct-p (cl-lib--con-2)))) 542 (should (mystruct-p (cl-lib--con-2))))
543 543
544(ert-deftest cl-lib-struct-with-accessors ()
545 (let ((x (make-mystruct :abc 1 :def 2)))
546 (cl-with-accessors ((abc mystruct-abc)
547 (def mystruct-def))
548 x
549 (should (= abc 1))
550 (should-error (setf abc 99))
551 (should (= def 2))
552 (setf def 3)
553 (should (= def 3))
554 (setq def 4)
555 (should (= def 4)))
556 (should (= 4 (mystruct-def x)))
557 (should (= 1 (mystruct-abc x)))))
558
544(ert-deftest cl-lib-arglist-performance () 559(ert-deftest cl-lib-arglist-performance ()
545 ;; An `&aux' should not cause lambda's arglist to be turned into an &rest 560 ;; An `&aux' should not cause lambda's arglist to be turned into an &rest
546 ;; that's parsed by hand. 561 ;; that's parsed by hand.