Common Lisp Extensions. Node: Time of Evaluation

PREV Argument Lists UP Program Structure NEXT Function Aliases

3.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.

Special Form: 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 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 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 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 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:
(eval-when (compile)           (setq foo1 'bar))
(eval-when (load)              (setq foo2 'bar))
(eval-when (compile load)      (setq foo3 'bar))
(eval-when (eval)              (setq foo4 'bar))
(eval-when (eval compile)      (setq foo5 'bar))
(eval-when (eval load)         (setq foo6 'bar))
(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 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 (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 (eval-when (compile load eval) ...).

Emacs 19 includes two special forms related to eval-when. One of these, eval-when-compile, is not quite equivalent to any eval-when construct and is described below. This package defines a version of eval-when-compile for the benefit of Emacs 18 users.

The other form, (eval-and-compile ...), is exactly equivalent to `(eval-when (compile load eval) ...)' and so is not itself defined by this package.

Special Form: 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.

Special Form: 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, 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 load-time-value act exactly like progn.

(defun report ()
  (insert "This function was executed on: "
          ", compiled on: "
          (eval-when-compile (current-time-string))
          ;; or '#.(current-time-string) in real Common Lisp
          ", and loaded on: "
          (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: "
          ", compiled on: "
          '"Wed Jun 23 18:33:43 1993"
          ", and loaded on: "
PREV Argument Lists UP Program Structure NEXT Function Aliases