2.2 Time of Evaluation

Normally, the byte-compiler does not actually execute the forms in a file it compiles. For example, if a file contains (setq foo t), the act of compiling it will not actually set foo to t. This is true even if the setq was a top-level form (i.e., not enclosed in a defun or other form). Sometimes, though, you would like to have certain top-level forms evaluated at compile-time. For example, the compiler effectively evaluates defmacro forms at compile-time so that later parts of the file can refer to the macros that are defined.

Macro: cl-eval-when (situations…) forms…

This form controls when the body forms are evaluated. The situations list may contain any set of the symbols compile, load, and eval (or their long-winded ANSI equivalents, :compile-toplevel, :load-toplevel, and :execute).

The cl-eval-when form is handled differently depending on whether or not it is being compiled as a top-level form. Specifically, it gets special treatment if it is being compiled by a command such as byte-compile-file which compiles files or buffers of code, and it appears either literally at the top level of the file or inside a top-level progn.

For compiled top-level cl-eval-whens, the body forms are executed at compile-time if compile is in the situations list, and the forms are written out to the file (to be executed at load-time) if load is in the situations list.

For non-compiled-top-level forms, only the eval situation is relevant. (This includes forms executed by the interpreter, forms compiled with byte-compile rather than byte-compile-file, and non-top-level forms.) The cl-eval-when acts like a progn if eval is specified, and like nil (ignoring the body forms) if not.

The rules become more subtle when cl-eval-whens are nested; consult Steele (second edition) for the gruesome details (and some gruesome examples).

Some simple examples:

;; Top-level forms in foo.el:
(cl-eval-when (compile)           (setq foo1 'bar))
(cl-eval-when (load)              (setq foo2 'bar))
(cl-eval-when (compile load)      (setq foo3 'bar))
(cl-eval-when (eval)              (setq foo4 'bar))
(cl-eval-when (eval compile)      (setq foo5 'bar))
(cl-eval-when (eval load)         (setq foo6 'bar))
(cl-eval-when (eval compile load) (setq foo7 'bar))

When foo.el is compiled, these variables will be set during the compilation itself:

foo1  foo3  foo5  foo7      ; 'compile'

When foo.elc is loaded, these variables will be set:

foo2  foo3  foo6  foo7      ; 'load'

And if foo.el is loaded uncompiled, these variables will be set:

foo4  foo5  foo6  foo7      ; 'eval'

If these seven cl-eval-whens had been, say, inside a defun, then the first three would have been equivalent to nil and the last four would have been equivalent to the corresponding setqs.

Note that (cl-eval-when (load eval) …) is equivalent to (progn …) in all contexts. The compiler treats certain top-level forms, like defmacro (sort-of) and require, as if they were wrapped in (cl-eval-when (compile load eval) …).

Emacs includes two special forms related to cl-eval-when. See Eval During Compile in GNU Emacs Lisp Reference Manual. One of these, eval-when-compile, is not quite equivalent to any cl-eval-when construct and is described below.

The other form, (eval-and-compile …), is exactly equivalent to ‘(cl-eval-when (compile load eval) …)’.

Macro: eval-when-compile forms…

The forms are evaluated at compile-time; at execution time, this form acts like a quoted constant of the resulting value. Used at top-level, eval-when-compile is just like ‘eval-when (compile eval)’. In other contexts, eval-when-compile allows code to be evaluated once at compile-time for efficiency or other reasons.

This form is similar to the ‘#.’ syntax of true Common Lisp.

Macro: cl-load-time-value form

The form is evaluated at load-time; at execution time, this form acts like a quoted constant of the resulting value.

Early Common Lisp had a ‘#,’ syntax that was similar to this, but ANSI Common Lisp replaced it with load-time-value and gave it more well-defined semantics.

In a compiled file, cl-load-time-value arranges for form to be evaluated when the .elc file is loaded and then used as if it were a quoted constant. In code compiled by byte-compile rather than byte-compile-file, the effect is identical to eval-when-compile. In uncompiled code, both eval-when-compile and cl-load-time-value act exactly like progn.

(defun report ()
  (insert "This function was executed on: "
          (current-time-string)
          ", compiled on: "
          (eval-when-compile (current-time-string))
          ;; or '#.(current-time-string) in real Common Lisp
          ", and loaded on: "
          (cl-load-time-value (current-time-string))))

Byte-compiled, the above defun will result in the following code (or its compiled equivalent, of course) in the .elc file:

(setq --temp-- (current-time-string))
(defun report ()
  (insert "This function was executed on: "
          (current-time-string)
          ", compiled on: "
          '"Wed Oct 31 16:32:28 2012"
          ", and loaded on: "
          --temp--))