summaryrefslogtreecommitdiff
path: root/lisp/emacs-lisp
diff options
context:
space:
mode:
authorEarl Hyatt <okamsn@protonmail.com>2025-03-12 23:01:49 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2025-03-31 14:29:48 -0400
commite04d1dafc700813c835ae4e45af4e104c49e8875 (patch)
tree405296248ee9da13e065213d8f88cfe317a7bc81 /lisp/emacs-lisp
parenta97a61b630624f5a6ec917db92e2985c56b20aa0 (diff)
downloademacs-e04d1dafc700813c835ae4e45af4e104c49e8875.tar.gz
emacs-e04d1dafc700813c835ae4e45af4e104c49e8875.tar.bz2
emacs-e04d1dafc700813c835ae4e45af4e104c49e8875.zip
Add cl-with-accessors
* lisp/emacs-lisp/cl-macs.el (cl-with-accessors): New macro. * doc/misc/cl.texi (Structures): Mention the new macro. * test/lisp/emacs-lisp/cl-macs-tests.el (cl-lib-struct-with-accessors): New Test. * etc/NEWS (New macro 'cl-with-accessors'.): Mention the macro. This macro is useful when making repeated use of a structures accessor functions, such as reading from a slot and then writing to a slot. It is similar to 'with-slots' from EIEIO, but uses accessor functions instead of slot names.
Diffstat (limited to 'lisp/emacs-lisp')
-rw-r--r--lisp/emacs-lisp/cl-macs.el44
1 files changed, 44 insertions, 0 deletions
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'."
collect `(,(car name) ,gensym))
,@body)))))
+;;;###autoload
+(defmacro cl-with-accessors (bindings instance &rest body)
+ "Use BINDINGS as function calls on INSTANCE inside BODY.
+
+This macro helps when writing code that makes repeated use of the
+accessor functions of a structure or object instance, such as those
+created by `cl-defstruct' and `defclass'.
+
+BINDINGS is a list of (NAME ACCESSOR) pairs. Inside BODY, NAME is
+treated as the function call (ACCESSOR INSTANCE) using
+`cl-symbol-macrolet'. NAME can be used with `setf' and `setq' as a
+generalized variable. Because of how the accessor is used,
+`cl-with-accessors' can be used with any generalized variable that can
+take a single argument, such as `car' and `cdr'.
+
+See also the macro `with-slots' described in the Info
+node `(eieio)Accessing Slots', which is similar, but uses slot names
+instead of accessor functions.
+
+\(fn ((NAME ACCESSOR) ...) INSTANCE &rest BODY)"
+ (declare (debug [(&rest (symbolp symbolp)) form body])
+ (indent 2))
+ (cond ((null body)
+ (macroexp-warn-and-return "`cl-with-accessors' used with empty body"
+ nil 'empty-body))
+ ((null bindings)
+ (macroexp-warn-and-return "`cl-with-accessors' used without accessors"
+ (macroexp-progn body)
+ 'suspicious))
+ (t
+ (cl-once-only (instance)
+ (let ((symbol-macros))
+ (dolist (b bindings)
+ (pcase b
+ (`(,(and (pred symbolp) var)
+ ,(and (pred symbolp) accessor))
+ (push `(,var (,accessor ,instance))
+ symbol-macros))
+ (_
+ (error "Malformed `cl-with-accessors' binding: %S" b))))
+ `(cl-symbol-macrolet
+ ,symbol-macros
+ ,@body))))))
+
;;; Multiple values.
;;;###autoload