GNU bug report logs -
#72344
[PATCH] Add a version of cl-once-only which handles lists of forms
Previous Next
Reported by: Thuna <thuna.cing <at> gmail.com>
Date: Sun, 28 Jul 2024 21:18:02 UTC
Severity: wishlist
Tags: patch
Done: Sean Whitton <spwhitton <at> spwhitton.name>
Bug is archived. No further changes may be made.
Full log
Message #47 received at 72344 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
>> If `cl-once-only-multiple' is fine by you then I would prefer that over
>> `cl-once-only-rest' and `cl-once-only-mult'. It would help to get more
>> suggestions, but I don't think anyone else will be chiming in at this
>> point.
>
> It's just really long :)
I do agree that it's decently long, but it's probably fine...?
`cl-destructuring-bind' is the same length and I don't find that too
annoying to write out, though maybe that's just me.
> Let's give ourselves time to think of something shorter.
I don't have any new ideas for the name, but here's a second draft which
tries to adapt the example used in `cl-once-only'. I was unable to get
the `mapcar' in the first example any more concise, so some thoughts on
rewording and fixing various parts of the text would be nice.
If Drew wants to start a new conversation to move `cl-once-only' (and
also this) out of cl-lib we can also just go with any name now and then
finalize it afterwards, though of all the names the one I favor is still
`cl-once-only-multiple' above all others (sans `cl-once-only*' which is
not an option - unless if you changed your mind about it?).
[cl-texi-second-draft.patch (text/x-patch, inline)]
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index 57e2f3a6c3b..de9f0565d03 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -2684,10 +2684,10 @@ Macro-Writing Macros
@end defmac
@defmac cl-once-only* (variable forms) body
-This macro is a version of @code{cl-once-only} which takes a list of
-forms. This macro is primarily meant to be used where the number of
-forms is unknown and thus @code{cl-once-only} cannot work, such as those
-obtained by a @code{&body} argument.
+This macro is a version of @code{cl-once-only} which takes an
+arbitrarily long list of forms. This macro is primarily meant to be
+used where the number of forms is unknown and thus @code{cl-once-only}
+cannot work, such as those obtained by a @code{&body} argument.
Each element of @var{variable} may be used to refer to the result of
evaluating the corresponding form in @var{forms} within @var{body}.
@@ -2696,38 +2696,58 @@ Macro-Writing Macros
such that each form is evaluated in order and its result is bound to the
corresponding symbol.
-Like @code{cl-once-only}, the first argument can be a symbol
-@var{variable}, which is equivalent to writing @code{(variable
-variable)}.
+Like @code{cl-once-only}, the first argument can be a symbol @var{variable}, which
+is equivalent to writing @code{(variable variable)}.
Consider the following macro:
@example
-(defmacro my-list (head &rest args)
- (cl-once-only ((args `(list ,@@args))
- `(list (apply #',head ,args)
- ,args
- (nth 1 ,args))))
+(defmacro my-list (vals &rest forms)
+ (let ((val-results (mapcar (lambda (_) (gensym)) vals)))
+ `(let* ,(cl-mapcar #'list val-results vals)
+ (list ,(cl-first val-results)
+ ,(cl-second val-results)
+ ,@@val-results
+ (progn ,@@forms)))))
@end example
-This macro is such that it will evaluate @var{args} only once, however
-that @var{args} was a list is lost once we are in @code{cl-once-only}.
-Furthermore, to access any specific element of @var{args} we must obtain
-the element during evaluation via @code{(nth N ,args)}.
+In a call like @code{(my-list ((pop foo) (cl-incf bar) ...) ...)} the
+@code{pop} and @code{cl-incf} will be evaluated exactly once, ensuring
+their side effects are not applied twice. This code is however very
+complex, in the same way code not using @code{cl-once-only} is.
-Consider the alternative using @code{cl-once-only*}:
+Using @code{cl-once-only} is not possible directly due to it expecting
+individual forms which can be evaluated. This can be worked around by
+assigning to a variable @code{`(list ,@@vars)} which @emph{can} be
+evaluated:
@example
-(defmacro my-list (head &rest args)
- (cl-once-only* args
- `(list (,head ,@@args)
- (list ,@@args)
- ,(nth 1 args))))
+(defmacro my-list (vals &rest forms)
+ (cl-once-only ((vals `(list ,@@vals)))
+ `(list (cl-first ,vals)
+ (cl-second ,vals)
+ ,vals ; Does not splice
+ (progn ,@@forms))))
+@end example
+
+There are two problems which both result from the fact that @code{vals}
+is not a list inside the body of @code{cl-once-only}: 1. @code{vals}
+cannot be spliced in the way it can in the previous example and
+2. accessing individual elements of @code{vals} can only be done by
+accessing the resulting list @emph{during evaluation}. Compare this to
+the example using @code{cl-once-only*}:
+
+@example
+(defmacro my-list (vals &rest forms)
+ (cl-once-only* vals
+ `(list ,(cl-first vals)
+ ,(cl-second vals)
+ ,@@vals
+ (progn ,@@forms))))
@end example
-which preserves the fact that @var{args} is a list and allows immediate
-access to individual arguments by simply choosing the corresponding
-element in @var{args}.
+which preserves the fact the @var{vals} is a list and removes
+boiler-plate code for generating and assigning temporary variables.
@end defmac
@node Macros
This bug report was last modified 95 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.