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.
- 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, andeval(or their long-winded ANSI equivalents,:compile-toplevel,:load-toplevel, and:execute).The
cl-eval-whenform 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 asbyte-compile-filewhich compiles files or buffers of code, and it appears either literally at the top level of the file or inside a top-levelprogn.For compiled top-level
cl-eval-whens, the body forms are executed at compile-time ifcompileis in the situations list, and the forms are written out to the file (to be executed at load-time) ifloadis in the situations list.For non-compiled-top-level forms, only the
evalsituation is relevant. (This includes forms executed by the interpreter, forms compiled withbyte-compilerather thanbyte-compile-file, and non-top-level forms.) Thecl-eval-whenacts like aprognifevalis specified, and likenil(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 adefun, then the first three would have been equivalent toniland the last four would have been equivalent to the correspondingsetqs.Note that
(cl-eval-when (load eval) …)is equivalent to(progn …)in all contexts. The compiler treats certain top-level forms, likedefmacro(sort-of) andrequire, 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-compileis just like ‘eval-when (compile eval)’. In other contexts,eval-when-compileallows 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-valueand gave it more well-defined semantics.In a compiled file,
cl-load-time-valuearranges for form to be evaluated when the .elc file is loaded and then used as if it were a quoted constant. In code compiled bybyte-compilerather thanbyte-compile-file, the effect is identical toeval-when-compile. In uncompiled code, botheval-when-compileandcl-load-time-valueact exactly likeprogn.(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--))