* bug#61179: lambda inside interactive form of around advice isn't a closure
@ 2023-01-30 15:48 Jonas Bernoulli
2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 2 replies; 13+ messages in thread
From: Jonas Bernoulli @ 2023-01-30 15:48 UTC (permalink / raw)
To: 61179; +Cc: Stefan Monnier
A function used as an around advice may advise the advised function's
interactive form, using (interactive (lambda (spec) ...)).
Unfortunately this inner lambda expression is not turned into a closure
as demonstrated by this simple example:
;; -*- lexical-binding: t -*-
(let ((var :value))
(lambda (fn &rest args)
(interactive
(lambda (spec)
(message "interactive: %s" var)
(advice-eval-interactive-spec spec)))
(message "body: %s" var)
(apply fn args)))
Or if you want to observe the failure when trying to use such an advice:
(defun -make-advice ()
(let ((var :value))
(lambda (fn &rest args)
(interactive
(lambda (spec)
(message "interactive: %s" var)
(advice-eval-interactive-spec spec)))
(message "body: %s" var)
(apply fn args))))
(defun -command (arg)
(interactive (list (read-string ": "))))
(advice-add '-command :around (-make-advice) '((name . "-advice")))
Could this be changed in the next Emacs release? Even if this should
make it into 29.1 (which I doubt), it would still be very useful for me
if this could somehow be rewritten to also work in older Emacs releases.
I have tried throwing an eval or two in there, but with limited success.
This gives me an inner closure, but the outside closure does not capture
the same environment it seems:
(let ((var :value))
(eval `(lambda (fn &rest args)
(interactive
,(lambda (spec)
(message "interactive: %s" var)
(advice-eval-interactive-spec spec)))
(message "body: %s" var)
(apply fn args))
t))
I got desperate and also tried things like:
(call-interactively
(let ((lex '((var . :value))))
(eval `(lambda ()
(interactive
,(eval '(lambda (spec)
(message "interactive: %s" var)
nil)
lex))
(message "body: %s" var))
lex)))
Thanks for your help!
Jonas
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-01-30 15:48 bug#61179: lambda inside interactive form of around advice isn't a closure Jonas Bernoulli
@ 2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-01 1:33 ` Jonas Bernoulli
2023-02-01 22:29 ` Jonas Bernoulli
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
1 sibling, 2 replies; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-01-31 23:33 UTC (permalink / raw)
To: Jonas Bernoulli; +Cc: 61179
> Unfortunately this inner lambda expression is not turned into a closure
> as demonstrated by this simple example:
>
> ;; -*- lexical-binding: t -*-
> (let ((var :value))
> (lambda (fn &rest args)
> (interactive
> (lambda (spec)
> (message "interactive: %s" var)
> (advice-eval-interactive-spec spec)))
> (message "body: %s" var)
> (apply fn args)))
Hmm... in Emacs-29, we fixed a part of this problem.
E.g.
(call-interactively
(let ((x 42))
(lambda (f)
(interactive (list (lambda () x)))
(+ (funcall f) 1))))
should return 43 (even when byte-compiled).
But indeed, the fix currently fails to account for such
"interactive advice" :-(
> Could this be changed in the next Emacs release? Even if this should
> make it into 29.1 (which I doubt), it would still be very useful for me
> if this could somehow be rewritten to also work in older Emacs releases.
The above fix is non-trivial, I'm afraid (e.g. it relies on OClosures
internally). For your above code, I think I'd try something like:
(let* ((var :value)
(interactive-advice
(lambda (spec)
(message "interactive: %s" var)
(advice-eval-interactive-spec spec)))
(advice-body
(lambda (fn &rest args)
(message "body: %s" var)
(apply fn args))))
(eval `(lambda (&rest args)
(interactive ,interactive-advice)
(apply ',advice-body args))
t))
where the last 4 lines are "generic" and could be turned into
a helper function if you end up using it several times.
This should also minimize the amount of code that's hidden from the
compiler by the backquote.
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-02-01 1:33 ` Jonas Bernoulli
2023-02-01 22:34 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-01 22:29 ` Jonas Bernoulli
1 sibling, 1 reply; 13+ messages in thread
From: Jonas Bernoulli @ 2023-02-01 1:33 UTC (permalink / raw)
To: Stefan Monnier; +Cc: 61179
Stefan Monnier <monnier@iro.umontreal.ca> writes:
> I think I'd try something like:
>
> (let* ((var :value)
> (interactive-advice
> (lambda (spec)
> (message "interactive: %s" var)
> (advice-eval-interactive-spec spec)))
> (advice-body
> (lambda (fn &rest args)
> (message "body: %s" var)
> (apply fn args))))
> (eval `(lambda (&rest args)
> (interactive ,interactive-advice)
> (apply ',advice-body args))
> t))
I'm having troubles falling asleep because my brain insists on rewording
the following (even though --or perhaps exactly because-- there is not
really any need to mention it at all). So I might as well try if typing
it out helps. ;)
I actually though of that, and the initial poc worked. I did that late
at night also updated transient to use it. In the morning I noticed
that there actually were many errors, and while I suspected that the
failure had nothing to do with this part of my change, it still lost
confidence in that approach, and since I felt some pressure to get
things done before the Emacs pre-release I stopped pursuing it.
Somehow I forgot about it when I wrote the above.
Now that you have suggested the same, my confidence is back. And now
that I have written the above, I should also be able to fall asleep. ;P
> where the last 4 lines are "generic" and could be turned into
> a helper function if you end up using it several times.
> This should also minimize the amount of code that's hidden from the
> compiler by the backquote.
I'll only need it once; would you recommend using a helper in that case
too?
>
>
> Stefan
Good night!
Jonas
zzzzZZz
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-01 1:33 ` Jonas Bernoulli
@ 2023-02-01 22:34 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-02 14:39 ` Jonas Bernoulli
0 siblings, 1 reply; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-01 22:34 UTC (permalink / raw)
To: Jonas Bernoulli; +Cc: 61179
> I'm having troubles falling asleep because my brain insists on rewording
> the following (even though --or perhaps exactly because-- there is not
> really any need to mention it at all). So I might as well try if typing
> it out helps. ;)
>
> I actually though of that, and the initial poc worked. I did that late
> at night also updated transient to use it. In the morning I noticed
> that there actually were many errors, and while I suspected that the
> failure had nothing to do with this part of my change, it still lost
> confidence in that approach, and since I felt some pressure to get
> things done before the Emacs pre-release I stopped pursuing it.
> Somehow I forgot about it when I wrote the above.
>
> Now that you have suggested the same, my confidence is back. And now
> that I have written the above, I should also be able to fall asleep. ;P
I hope your slept well. The code I sent is, as usual, 100% guaranteed
untested, but it *should* work modulo silly errors.
> I'll only need it once; would you recommend using a helper in that case too?
Either way works.
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-01 1:33 ` Jonas Bernoulli
@ 2023-02-01 22:29 ` Jonas Bernoulli
1 sibling, 0 replies; 13+ messages in thread
From: Jonas Bernoulli @ 2023-02-01 22:29 UTC (permalink / raw)
To: Stefan Monnier; +Cc: 61179
Stefan,
Could you please have a look at bug#61176 too? The reason I am
looking into this around advice business in the first place, is
that `post-command-hook' isn't quite working as I expected, as
described in that issue.
Thanks!
Jonas
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-01-30 15:48 bug#61179: lambda inside interactive form of around advice isn't a closure Jonas Bernoulli
2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-04 23:47 ` Michael Heerdegen
` (2 more replies)
1 sibling, 3 replies; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-04 16:26 UTC (permalink / raw)
To: Jonas Bernoulli; +Cc: 61179
> A function used as an around advice may advise the advised function's
> interactive form, using (interactive (lambda (spec) ...)).
>
> Unfortunately this inner lambda expression is not turned into a closure
> as demonstrated by this simple example:
I installed a patch in `master` which should fix this problem, both for
the case where the code is interpreted and for the case where it is
byte-compiled.
Could you confirm that it works for you?
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
@ 2023-02-04 23:47 ` Michael Heerdegen
2023-02-05 14:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-05 16:43 ` Jonas Bernoulli
2023-02-08 14:38 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2 siblings, 1 reply; 13+ messages in thread
From: Michael Heerdegen @ 2023-02-04 23:47 UTC (permalink / raw)
To: 61179; +Cc: jonas, monnier
[-- Attachment #1: Type: text/plain, Size: 927 bytes --]
Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <bug-gnu-emacs@gnu.org> writes:
> I installed a patch in `master` which should fix this problem, both for
> the case where the code is interpreted and for the case where it is
> byte-compiled.
Very good.
This seems to break some of my private code. Didn't look into your
change so far.
My code generates function advices with the following semantics: You
specify an alternative function and a condition (as a predicate
function). When the advice is enabled, whenever the function is called
the predicate is first checked for a non-nil result. When non-nil, the
alternative function that had been specified is called (recursive calls
are bot affected however). When nil, the original function is called.
I'm using this hack only in my init file for convenience, I like the
semantics for this purpose.
Here is a recipe for emacs -Q:
[-- Attachment #2: int-lambda.el --]
[-- Type: application/emacs-lisp, Size: 2208 bytes --]
[-- Attachment #3: Type: text/plain, Size: 610 bytes --]
Worked as I wanted until now. But with your patch installed when
compiling the above snipped I get a *Compile Log* saying:
| Compiling internal form(s) at Sun Feb 5 00:36:11 2023
| int-lambda.elc: Error: ‘lambda’ defined after use in (lambda (old-spec3) (let ((test-result0 (#[0 "\300\207" [t] 1]))) (cons (if test-result0 'mel-ad-run-replacement 'mel-ad-run-original) (advice-eval-interactive-spec (if (not test-result0) old-spec3))))) (missing ‘require’ of a library file?)
| int-lambda.elc: Error: ‘lambda’ used as function name is invalid
Who is to blame?
TIA,
Michael.
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-04 23:47 ` Michael Heerdegen
@ 2023-02-05 14:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-05 22:23 ` Michael Heerdegen
0 siblings, 1 reply; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-05 14:05 UTC (permalink / raw)
To: Michael Heerdegen; +Cc: Jonas Bernoulli, 61179
> | Compiling internal form(s) at Sun Feb 5 00:36:11 2023
> | int-lambda.elc: Error: ‘lambda’ defined after use in (lambda (old-spec3)
> | (let ((test-result0 (#[0 "\300\207" [t] 1]))) (cons (if test-result0
> | 'mel-ad-run-replacement 'mel-ad-run-original)
> | (advice-eval-interactive-spec (if (not test-result0) old-spec3)))))
> | (missing ‘require’ of a library file?)
> | int-lambda.elc: Error: ‘lambda’ used as function name is invalid
>
> Who is to blame?
You, of course.
But I think the patch below (which I just pushed to `master`) will help,
Stefan
diff --git a/lisp/emacs-lisp/cconv.el b/lisp/emacs-lisp/cconv.el
index e4268c2fb88..e8d639903c1 100644
--- a/lisp/emacs-lisp/cconv.el
+++ b/lisp/emacs-lisp/cconv.el
@@ -488,7 +488,7 @@ cconv-convert
(_ (pcase cif
('nil nil)
(`#',f
- (setf (cadr (car bf)) (if wrapped (nth 2 f) f))
+ (setf (cadr (car bf)) (if wrapped (nth 2 f) cif))
(setq cif nil))
;; The interactive form needs special treatment, so the form
;; inside the `interactive' won't be used any further.
^ permalink raw reply related [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-04 23:47 ` Michael Heerdegen
@ 2023-02-05 16:43 ` Jonas Bernoulli
2023-02-05 18:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-08 14:38 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2 siblings, 1 reply; 13+ messages in thread
From: Jonas Bernoulli @ 2023-02-05 16:43 UTC (permalink / raw)
To: Stefan Monnier; +Cc: 61179
Stefan Monnier <monnier@iro.umontreal.ca> writes:
>> A function used as an around advice may advise the advised function's
>> interactive form, using (interactive (lambda (spec) ...)).
>>
>> Unfortunately this inner lambda expression is not turned into a closure
>> as demonstrated by this simple example:
>
> I installed a patch in `master` which should fix this problem, both for
> the case where the code is interpreted and for the case where it is
> byte-compiled.
>
> Could you confirm that it works for you?
Thanks a lot! I'll try it out tomorrow (it doesn't seem my brain feels
like work today).
Jonas
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-05 16:43 ` Jonas Bernoulli
@ 2023-02-05 18:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
0 siblings, 0 replies; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-05 18:54 UTC (permalink / raw)
To: Jonas Bernoulli; +Cc: 61179
> Thanks a lot! I'll try it out tomorrow (it doesn't seem my brain feels
> like work today).
Don't worry: mine is slowly thawing now, so there's no hurry,
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
* bug#61179: lambda inside interactive form of around advice isn't a closure
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-04 23:47 ` Michael Heerdegen
2023-02-05 16:43 ` Jonas Bernoulli
@ 2023-02-08 14:38 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2 siblings, 0 replies; 13+ messages in thread
From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-02-08 14:38 UTC (permalink / raw)
To: 61179-done
> Could you confirm that it works for you?
[ Confirmed. ]
Thanks, closing,
Stefan
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2023-02-08 14:38 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-01-30 15:48 bug#61179: lambda inside interactive form of around advice isn't a closure Jonas Bernoulli
2023-01-31 23:33 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-01 1:33 ` Jonas Bernoulli
2023-02-01 22:34 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-02 14:39 ` Jonas Bernoulli
2023-02-01 22:29 ` Jonas Bernoulli
2023-02-04 16:26 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-04 23:47 ` Michael Heerdegen
2023-02-05 14:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-05 22:23 ` Michael Heerdegen
2023-02-05 16:43 ` Jonas Bernoulli
2023-02-05 18:54 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2023-02-08 14:38 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).