that depend on dynamic state; for instance, calls to proclaim permanently change the way
eval binds variables!
To address this problem, compilers can support a subjunctive environment [9], a special LISP
environment which is quarantined from the current environment for the purposes of compilation.
(IBM's Yorktown Lisp compiler provided saved states for this purpose [10]). A LISP environment
is presumably everything with dynamic extent that can be changed by evaluating top-level
forms in user code; it can include the data for the reader, definitions for macros, structures,
setf methods, and types, special proclamations, and even function definitions. The purpose of
a subjunctive environment is to insulate the current environment from side-effects of using the
compiler. The compiler runs in its own subjunctive environment.
MuItiple-file compilation complicates the matter. If compile-file is called on several files,
side-effects from compiling early files should be available for compiling later files. If each
compilation produced a fresh subjunctive environment, then the early files would have to be
reloaded for each later file that needed them. Alternately, a single subjunctive environment for
all compilations would suffer some of the problems of no subjunctive environment -- it could be
permanently corrupted. Furthermore, it is common for LISP programmers to load in a personal
customization of the "bare" implementation once, and compile a series of files during a session
that may need the personal definitions. Thus a subjunctive environment would at least need
read-access to the user's environment.
Given the complexity of implementing subjunctive environments and the lack of direction
from CLtL, it is best to assume that implementations will differ in how they handle the
problem.11
An implementation may support a partial subjunctive environment; for instance,
an implementation may treat macro and structure definitions as implicit eva1-when forms, or
may keep a separate compiler-only database.
The ambiguity over handling compiler side-effects has ramifications for writing portable `
program analysis utilities and for writing portable COMMON LISP programs. Program analysis
utilities mimic the compiler when processing forms. Since implementations may or may not
support subjunctive environments for compilation, a portable program analysis tool cannot be
guaranteed to process forms exactly like the local compiler. Furthermore, there appears to be no
portable way to support a subjunctive environment for compiler side-effects. CLtL notes that the
compiler must see the definition of a macro before the macro is called, but it is (appropriately)
silent on how the the compiler retrieves the expander function when it is needed. Similarly,
structure definitions and setf methods access private, implementation-dependent databases.
Packages are accessed in a single namespace, so there is also no portable way to protect the
state of the package system.
XREF does not maintain a subjunctive environment. The result is that XREF's "compiler"
side-effects occur in the user's development environment, although it takes some steps to minimize
the extent of side effects. Top-level package and readtable operations are evaluated in
the current environment, except that the current package and readtable bindings are saved and
*****************
11
Supporting a subjunctive environment is easier in some implementations, such as those with
UNIX12 fork-like
process primitives or copy-on-write memory management, and next to impossible in others, such as single
namespace Lisp workstations.
12
UNIX is a trademark of Bell Labs.
|