12

I was having fun adding some advice to a function:

(advice-add 'executable-find :around
            (lambda (f &rest args)
              (apply g args)))
               ;;;   ^

Ouch, a typo. Fixed it and evaluated above code again. But now I have both, the "corrected" and the "broken" advice around that function.

How do I get rid of these? Given that advice-remove needs either the function object or the around advice (which is empty here)?

(Obviously I can just quit and restart, but there's another way, is it?)

3 Answers 3

9

You can also call advice-remove with the same lambda expression, i.e., replace advice-add with advice-remove and delete :around, then C-x C-e.

2
  • This works! I thought it wouldn't, I assumed that (1) each time you evaluate a lambda form you get a new function not eq to the previous ones, (2) advice-remove would compare the function you pass it to the advices until it finds one that is eq to it and remove that, (3) even if advice-remove used a different test, like equal, it still wouldn't work, because different evaluations of a lambda form would not equal each other. Turns out (1) is correct, but (2) and (3) are wrong: advice-remove uses equal, and evaluating the same lambda twice produces equal results!
    – Omar
    Commented Jun 6, 2017 at 16:14
  • Noticed I didn't accept an answer back when I asked the question. I choose Yours because it's the IMO most helpful in the situation. Commented Feb 24, 2019 at 10:48
14

There's advice-mapc, which let's one iterate over all advices of some function, applying a given function to each. With it, it's easy to remove all advices:

(advice-mapc
  (lambda (adv prop)
    (advice-remove 'executable-find adv))
  'executable-find)

This could be extended to remove only advices which don't have a name property by looking in the second (props) argument (which is an alist) for those which do not have something associated to key name.

1
  • Yes. And using a name makes removing easier.
    – Drew
    Commented May 23, 2017 at 22:34
1

Here's some code to help doing just that, interactively.

This defines two functions. The first function gets the list of all advices on a given symbol, the second function interactively asks for a symbol and an advice on that symbol, then removes the latter from the former. As this all happens with completion, it's easier (to me) than copy pasting the lambda expression.

(defun yf/advice-list (symbol)
  (let (result)
    (advice-mapc
     (lambda (ad props)
       (push ad result))
     symbol)
    (nreverse result)))

(defun yf/kill-advice (symbol advice)
  "Kill ADVICE from SYMBOL."
  (interactive (let* ((sym (intern (completing-read "Function: " obarray #'yf/advice-list t)))
                      (advice (let ((advices-and-their-name
                                     (mapcar (lambda (ad) (cons (prin1-to-string ad)
                                                                ad))
                                             (yf/advice-list sym))))
                                (cdr (assoc (completing-read "Remove advice: " advices-and-their-name nil t)
                                            advices-and-their-name)))))
                 (list sym advice)))
  (advice-remove symbol advice))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.