Search code examples
emacselispevaldefadviceadvising-functions

whether and how to avoid eval in defadvice loop


Should one avoid eval in the following code? If so, how? Or is this one of exceptional cases where using eval is better?

(dolist (command '(....))
  (eval
   `(defadvice ,command (around blah activate)
      ...)))

For a real life example of the idiom above:

(dolist (command '(paredit-comment-dwim comment-dwim))
  (eval
   `(defadvice ,command (around my-check-parens-and-warn-for-comment activate)
      (if (and (called-interactively-p 'any)
               (use-region-p))
          (progn
            (my-check-parens-and-warn-if-mismatch "You commented out a region and introduced a mismatched paren")
            ad-do-it
            (my-check-parens-and-warn-if-mismatch "You uncommented out a region and introduced a mismatched paren"))
        ad-do-it))))

Solution

  • Two solutions:

    • Use ad-add-advice instead of defadvice.
    • If you're using Emacs trunk, you can use the new advice-add.

    Using advice-add would look like the following code:

    (defun my-check-commented-parens (orig-fun &rest args)
      (if (not (and (called-interactively-p 'any)
                    (use-region-p)))
          (apply orig-fun args)
        (my-check-parens-and-warn-if-mismatch "You commented out a region and introduced a mismatched paren")
        (apply orig-fun args)
        (my-check-parens-and-warn-if-mismatch "You uncommented out a region and introduced a mismatched paren")))
    
    (dolist (command '(paredit-comment-dwim comment-dwim))
      (advice-add command :around #'my-check-commented-parens))