cl: Time of Evaluation
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-when’s, 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-when’s 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-when’s 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 ‘setq’s.
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’.
(elisp)Eval During Compile. 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--))