When an EVAL-WHEN
is compiled as a non-top-level form, it's either compiled like a PROGN
, if the :execute
situation is specified, or ignored. Similarly, an evaluated EVAL-WHEN
—which includes top-level EVAL-WHEN
s in a source file processed by LOAD
and EVAL-WHEN
s evaluated at compile time because they appear as subforms of a top-level EVAL-WHEN
with the :compile-toplevel
situation—is treated like a PROGN
if :execute
is present and ignored otherwise.
Thus, a macro such as IN-PACKAGE
can have the necessary effect at both compile time and when loading from source by expanding into an EVAL-WHEN
like the following:
(eval-when (:compile-toplevel :load-toplevel :execute)
(setf *package* (find-package 'PACKAGE-NAME')))
*PACKAGE*
will be set at compile time because of the :compile- toplevel
situation, set when the FASL is loaded because of :load-toplevel
, and set when the source is loaded because of the :execute
.
There are two ways you're most likely to use EVAL-WHEN
. One is if you want to write macros that need to save some information at compile time to be used when generating the expansion of other macro forms in the same file. This typically arises with definitional macros where a definition early in a file can affect the code generated for a definition later in the same file. You'll write this kind of macro in Chapter 24.
The other time you might need EVAL-WHEN
is if you want to put the definition of a macro and helper functions it uses in the same file as code that uses the macro. DEFMACRO
already includes an EVAL- WHEN
in its expansion so the macro definition is immediately available to be used later in the file. But DEFUN
normally doesn't make function definitions available at compile time. But if you use a macro in the same file as it's defined in, you need the macro DEFUN
s of any helper functions used by the macro in an EVAL-WHEN
with :compile- toplevel
, the definitions will be available when the macro's expansion function runs. You'll probably want to include :load-toplevel
and :execute
as well since the macros will also need the function definitions after the file is compiled and loaded or if you load the source instead of compiling.
The four remaining special operators, LOCALLY
, THE
, LOAD-TIME-VALUE
, and PROGV
, all allow you to get at parts of the underlying language that can't be accessed any other way. LOCALLY
and THE
are part of Common Lisp's declaration system, which is used to communicate things to the compiler that don't affect the meaning of your code but that may help the compiler generate better code—faster, clearer error messages, and so on.[220] I'll discuss declarations briefly in Chapter 32.
The other two, LOAD-TIME-VALUE
and PROGV
, are infrequently used, and explaining the reason why you might ever
LOAD-TIME-VALUE
is used, as its name suggests, to create a value that's determined at load time. When the file compiler compiles code that contains a LOAD-TIME- VALUE
form, it arranges to evaluate the first subform once, when the FASL is loaded, and for the code containing the LOAD-TIME-VALUE
form to refer to that value. In other words, instead of writing this:
(defvar *loaded-at* (get-universal-time))
(defun when-loaded () *loaded-at*)
you can write the following:
(defun when-loaded () (load-time-value (get-universal-time)))
In code not processed by COMPILE-FILE
, LOAD-TIME- VALUE
is evaluated once when the code is compiled, which may be when you explicitly compile a function with COMPILE
or earlier because of implicit compilation performed by the implementation in the course of evaluating the code. In uncompiled code, LOAD-TIME- VALUE
evaluates its form each time it's evaluated.
Finally, PROGV
creates new dynamic bindings for variables whose names are determined at runtime. This is mostly useful for implementing embedded interpreters for languages with dynamically scoped variables. The basic skeleton is as follows:
(progv
where PROGV
and LET
is that because
And that's it for special operators. In the next chapter, I'll get back to hard-nosed practical topics and show you how to use Common Lisp's package system to take control of your namespaces so you can write libraries and applications that can coexist without stomping on each other's names.
21. Programming in the Large: Packages and Symbols
In Chapter 4 I discussed how the Lisp reader translates textual names into objects to be passed to the evaluator, representing them with a kind of object called a
Suppose, for instance, you're writing a program and decide to use a third-party library. You don't want to have to know the name of every function, variable, class, or macro used in the internals of that library in order to avoid conflicts between those names and the names you use in your program. You'd like for most of the names in the library and the names in your program to be considered distinct even if they happen to have the same textual representation. At the same time, you'd like certain names defined in the library to be readily accessible—the names that make up its public API, which you'll want to use in your program.
In Common Lisp, this namespace problem boils down to a question of controlling how the reader translates