在Emacs Lisp中,“with-eval-after-load”是什么?

41

我在尝试从这里安装persp-mode时,遇到了宏with-eval-after-load。但是我无法在Emacs和/或Google中找到该宏。它定义在哪里?它是标准的Emacs Lisp的一部分吗?

1个回答

64

来自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 在2014年10月20日发布。

eval-after-load 被认为是不规范的,因为它是一个函数而不是宏,所以需要引用它内部的代码,这意味着它不能被字节编译。它也只接受一个表达式,如果你有多个表达式,就需要使用 progn。例如:

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

使用 with-eval-after-load 的等效版本如下:

(with-eval-after-load "foo"
  (setq foo 42)
  (setq bar 17))
正如评论中Clément所指出的,使用with-eval-after-load的一个缺点是无法依赖于模块中定义的宏,而使用eval-after-load则可以确定该类宏已被定义且可供使用。这个问题在emacs-devel邮件列表上进行了讨论。

2
如果“更好的行为”只是指这些,那么我认为这几乎是虚假宣传。我真诚地希望在Emacs中添加此宏的原因不仅仅是NEWS中给出的原因。 - Drew
8
据我所知,with-eval-after-load 会安排对其主体进行字节编译,而 eval-after-load 则不会。这也是它被添加的主要原因。 - user355252
@lunaryorn: 啊,是的,那很有道理。(尽管通常主体并不会从编译中受益。而且字节编译并不一定会导致“更好的行为”。) 另一个重要的区别是(根据可怜的文档),宏显然会在每次加载 LIBRARY 时评估 BODY;而 eval-after-load 的目标之一就是不要这样做。 - Drew
3
我之前的想法是错误的,每次评估BODY确实会有不同。请参考Emacs bug #16810 - Drew
5
另一方面,with-eval-after-load 的语义略有不同:你不能(可靠地)在“with-eval-after-load 'foo”块中调用在包'foo'中定义的宏。 - Clément
@Clément,感谢你从Stefan那里获取了这些信息。我永远不会想到这是如何发生的,更不用说为什么了。 - hraban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接