1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

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.
This commit is contained in:
Earl Hyatt 2025-03-12 23:01:49 -04:00 committed by Stefan Monnier
parent a97a61b630
commit e04d1dafc7
4 changed files with 118 additions and 0 deletions

View file

@ -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