Subject: Re: bug#61179: lambda inside interactive form of around advice isn't a closure

From: Stefan Monnier <[email-masked]>
Date: Tue, 31 Jan 2023 18:33:18 -0500

> 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