41

I came across the macro with-eval-after-load when trying to install persp-mode from here. But I am unable to find the macro inside Emacs and/or on Google. Where is it defined? Is it part of standard Emacs Lisp?

itsjeyd
  • 5,070
  • 2
  • 30
  • 49
Talespin_Kit
  • 20,830
  • 29
  • 89
  • 135

1 Answers1

64

From etc/NEWS:

* Lisp Changes in Emacs 24.4
...
** New macro `with-eval-after-load'.
This is like the old `eval-after-load', but better behaved.

Emacs 24.4 was released on 20th October 2014.

eval-after-load is considered ill-behaved because it is a function, not a macro, and thus requires the code inside it to be quoted, which means that it cannot be byte-compiled. It also accepts only one form, so if you have more than one, you need to use progn. For example:

(eval-after-load "foo"
  '(progn
     (setq foo 42)
     (setq bar 17)))

The equivalent version with with-eval-after-load would be:

(with-eval-after-load "foo"
  (setq foo 42)
  (setq bar 17))

As noted by Clément in a comment, one disadvantage of with-eval-after-load is that you cannot rely on macros defined in the module in question, while with eval-after-load you can be sure that such macros are defined and available to use. This was discussed on emacs-devel.

legoscia
  • 39,593
  • 22
  • 116
  • 167
  • 2
    *FWIW:* If that's all that is meant by "better behaved" then I'd say that that is pretty much false advertising. I sincerely hope there is a better reason than what is given in the `NEWS` for bothering to add this macro to Emacs. – Drew Feb 19 '14 at 15:12
  • 8
    @Drew `with-eval-after-load` arranges for the body to be byte-compiled, whereas `eval-after-load` does not. That was the main reason for its addition, iirc. –  Feb 19 '14 at 17:57
  • @lunaryorn: Ah, yes, that makes sense. (Though often the body is not something that benefits much from compiling. And byte-compiling does not necessarily make for "better behavior".) Another important difference is that (according to the paltry doc) the macro apparently evaluates `BODY` "***each time*** `LIBRARY` is loaded". (*Not* doing that is one of the aims of `eval-after-load`.) – Drew Feb 19 '14 at 18:50
  • 3
    @lunaryorn: I was wrong that evaluating `BODY` each time is a difference. See Emacs [bug #16810](http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16810). – Drew Feb 19 '14 at 19:38
  • 5
    On the other hand, the semantics of with-eval-after-load are subtly different: you can't (reliably) call a macro defined in package `foo` in a `with-eval-after-load 'foo` block. https://lists.gnu.org/archive/html/emacs-devel/2018-02/msg00714.html – Clément Feb 26 '18 at 05:35
  • @Clément thank you for prying that info from Stefan. I would never have figured out how or why this was happening. – hraban Sep 03 '21 at 00:48