Common Lisp the Language, 2nd Edition
Next: Accessing Directories
Up: File System Interface
Previous: RenamingDeleting,
and
To load a file is to read through the file, evaluating each
form in it. Programs are typically stored in files containing calls to
constructs such as defun
, defmacro
, and
defvar
, which define the functions and variables of the
program.
Loading a compiled (``fasload’’) file is similar, except that the file does not contain text but rather pre-digested expressions created by the compiler that can be loaded more quickly.
[Function]
load
filename
&key :verbose :print :if-does-not-exist
This function loads the file named by filename into the Lisp
environment. It is assumed that a text (character file) can be
automatically distinguished from an object (binary) file by some
appropriate implementation-dependent means, possibly by the file type.
The defaults for filename are taken from the variable
*default-pathname-defaults*
. If the filename
(after the merging in of the defaults) does not explicitly specify a
type, and both text and object types of the file are available in the
file system, load
should try to select the more appropriate
file by some implementation-dependent means.
If the first argument is a stream rather than a pathname, then
load
determines what kind of stream it is and loads
directly from the stream.
The :verbose
argument (which defaults to the value of
*load-verbose*
), if true, permits load
to
print a message in the form of a comment (that is, with a leading
semicolon) to *standard-output*
indicating what file is
being loaded and other useful information.
The :print
argument (default nil
), if true,
causes the value of each expression loaded to be printed to
*standard-output*
. If a binary file is being loaded, then
what is printed may not reflect precisely the contents of the source
file, but nevertheless some information will be printed.
X3J13 voted in March 1989 (COMPILER-VERBOSITY) to add the variable
*load-print*
; its value is used as the default for the
:print
argument to load
.
The function load
rebinds *package*
to its
current value. If some form in the file changes the value of
*package*
during loading, the old value will be restored
when the loading is completed. (This was specified in the first edition
under the description of *package*
; for convenience I now
mention it here as well.)
X3J13 voted in March 1988 (PATHNAME-STREAM) to specify exactly which streams may be used as pathnames. See section 23.1.6.
X3J13 voted in June 1989 (PATHNAME-WILD) to clarify that supplying
a wild pathname as the filename argument to load
has implementation-dependent consequences; load
might
signal an error, for example, or might load all files that match the
pathname.
X3J13 voted in June 1989 (PATHNAME-LOGICAL) to require
load
to accept logical pathnames (see section 23.1.5).
If a file is successfully loaded, load
always returns a
non-nil
value. If :if-does-not-exist
is
specified and is nil
, load
just returns
nil
rather than signaling an error if the file does not
exist.
X3J13 voted in March 1989 (IN-SYNTAX) to require that
load
bind *readtable*
to its current value at
the time load
is called; the dynamic extent of the binding
should encompass all of the file-loading activity. This allows a
portable program to include forms such as
(in-package "FOO")
(eval-when (:execute :load-toplevel :compile-toplevel)
(setq *readtable* foo:my-readtable))
without performing a net global side effect on the loading
environment. Such statements allow the remainder of such a file to be
read either as interpreted code or by compile-file
in a
syntax determined by an alternative readtable.
X3J13 voted in June 1989 (LOAD-TRUENAME) to require that
load
bind two new variables *load-pathname*
and *load-truename*
; the dynamic extent of the bindings
should encompass all of the file-loading activity.
[Variable]
*load-verbose*
This variable provides the default for the :verbose
argument to load
. Its initial value is
implementation-dependent.
[Variable]
*load-print*
X3J13 voted in March 1989 (COMPILER-VERBOSITY) to add
*load-print*
. This variable provides the default for the
:print
argument to load
. Its initial value is
nil
.
[Variable]
*load-pathname*
X3J13 voted in June 1989 (LOAD-TRUENAME) to introduce
*load-pathname*
; it is initially nil
but
load
binds it to a pathname that represents the file name
given as the first argument to load
merged with the
defaults (see merge-pathname
).
[Variable]
*load-truename*
X3J13 voted in June 1989 (LOAD-TRUENAME) to introduce
*load-truename*
; it is initially nil
but
load
binds it to the ``true name’’ of the file being
loaded. See truename
.
X3J13 voted in March 1989 (LOAD-OBJECTS) to introduce a facility
based on the Object System whereby a user can specify how
compile-file
and load
must cooperate to
reconstruct compile-time constant objects at load time. The protocol is
simply this: compile-file
calls the generic function
make-load-form
on any object that is referenced as a
constant or as a self-evaluating form, if the object’s metaclass is
standard-class
, structure-class
, any
user-defined metaclass (not a subclass of built-in-class
),
or any of a possibly empty implementation-defined list of other
metaclasses; compile-file
will call
make-load-form
only once for any given object (as
determined by eq
) within a single file. The
user-programmability stems from the possibility of user-defined methods
for make-load-form
. The helper function
make-load-form-saving-slots
makes it easy to write commonly
used versions of such methods.
[Generic function]
make-load-form
object
The argument is an object that is referenced as a constant or as a
self-evaluating form in a file being compiled by
compile-file
. The objective is to enable load
to construct an equivalent object.
The first value, called the creation form, is a form that,
when evaluated at load time, should return an object that is equivalent
to the argument. The exact meaning of ``equivalent’’ depends on the type
of object and is up to the programmer who defines a method for
make-load-form
. This allows the user to program the notion
of ``similar as a constant’’ (see section 25.1).
The second value, called the initialization form, is a form
that, when evaluated at load time, should perform further initialization
of the object. The value returned by the initialization form is ignored.
If the make-load-form
method returns only one value, the
initialization form is nil
, which has no effect. If the
object used as the argument to make-load-form
appears as a
constant in the initialization form, at load time it will be replaced by
the equivalent object constructed by the creation form; this is how the
further initialization gains access to the object.
Two values are returned so that circular structures may be handled. The order of evaluation rules discussed below for creation and initialization forms eliminates the possibility of partially initialized objects in the absence of circular structures and reduces the possibility to a minimum in the presence of circular structures. This allows nodes in non-circular structures to be built out of fully initialized subparts.
Both the creation form and the initialization form can contain references to objects of user-defined types (defined precisely below). However, there must not be any circular dependencies in creation forms. An example of a circular dependency: the creation form for the object X contains a reference to the object Y, and the creation form for the object Y contains a reference to the object X. A simpler example: the creation form for the object X contains a reference to X itself. Initialization forms are not subject to any restriction against circular dependencies, which is the entire reason for having initialization forms. See the example of circular data structures below.
The creation form for an object is always evaluated before the
initialization form for that object. When either the creation form or
the initialization form refers to other objects of user-defined types
that have not been referenced earlier in the compile-file
,
the compiler collects all of the creation and initialization forms. Each
initialization form is evaluated as soon as possible after its creation
form, as determined by data flow. If the initialization form for an
object does not refer to any other objects of user-defined types that
have not been referenced earlier in the compile-file
, the
initialization form is evaluated immediately after the creation form. If
a creation or initialization form F references other objects of
user-defined types that have not been referenced earlier in the
compile-file
, the creation forms for those other objects
are evaluated before F and the initialization forms for those
other objects are also evaluated before F whenever they do not
depend on the object created or initialized by F. Where the
above rules do not uniquely determine an order of evaluation, it is
unspecified which of the possible orders of evaluation is chosen.
While these creation and initialization forms are being evaluated,
the objects are possibly in an uninitialized state, analogous to the
state of an object between the time it has been created by
allocate-instance
and it has been processed fully by
initialize-instance
. Programmers writing methods for
make-load-form
must take care in manipulating objects not
to depend on slots that have not yet been initialized.
It is unspecified whether load
calls eval
on the forms or does some other operation that has an equivalent effect.
For example, the forms might be translated into different but equivalent
forms and then evaluated; they might be compiled and the resulting
functions called by load
(after they themselves have been
loaded); or they might be interpreted by a special-purpose interpreter
different from eval
. All that is required is that the
effect be equivalent to evaluating the forms.
It is valid for user programs to call make-load-form
in
circumstances other than compilation, providing the argument’s metaclass
is not built-in-class
or a subclass of
built-in-class
.
Applying make-load-form
to an object whose metaclass is
standard-class
or structure-class
for which no
user-defined method is applicable signals an error. It is valid to
implement this either by defining default methods for the classes
standard-object
and structure-object
that
signal an error or by having no applicable method for those classes.
See load-time-eval
.
In the following example, an equivalent instance of
my-class
is reconstructed by using the values of two of its
slots. The value of the third slot is derived from those two values.
(defclass my-class ()
((a :initarg :a :reader my-a)
(b :initarg :b :reader my-b)
(c :accessor my-c)))
(defmethod shared-initialize ((self my-class) slots &rest inits)
(declare (ignore slots inits))
(unless (slot-boundp self 'c)
(setf (my-c self)
(some-computation (my-a self) (my-b self)))))
(defmethod make-load-form ((self my-class))
`(make-instance ',(class-name (class-of self))
:a ',(my-a self) :b ',(my-b self)))
This code will fail if either of the first two slots of some instance
of my-class
contains the instance itself. Another way to
write the last form in the preceding example is
(defmethod make-load-form ((self my-class))
(make-load-form-saving-slots self '(a b)))
This has the advantages of conciseness and handling circularities correctly.
In the next example, instances of class my-frob
are
``interned’’ in some way. An equivalent instance is reconstructed by
using the value of the name
slot as a key for searching for
existing objects. In this case the programmer has chosen to create a new
object if no existing object is found; an alternative possibility would
be to signal an error in that case.
(defclass my-frob ()
((name :initarg :name :reader my-name)))
(defmethod make-load-form ((self my-frob))
`(find-my-frob ',(my-name self) :if-does-not-exist :create))
In the following example, the data structure to be dumped is circular, because each node of a tree has a list of its children and each child has a reference back to its parent.
(defclass tree-with-parent () ((parent :accessor tree-parent)
(children :initarg :children)))
(defmethod make-load-form ((x tree-with-parent))
(values
`(make-instance ',(class-of x)
:children ',(slot-value x 'children))
`(setf (tree-parent ',x) ',(slot-value x 'parent))))
Suppose make-load-form
is called on one object in such a
structure. The creation form creates an equivalent object and fills in
the children
slot, which forces creation of equivalent
objects for all of its children, grandchildren, etc. At this point none
of the parent slots have been filled in. The initialization form fills
in the parent
slot, which forces creation of an equivalent
object for the parent if it was not already created. Thus the entire
tree is recreated at load time. At compile time,
make-load-form
is called once for each object in the tree.
All the creation forms are evaluated, in unspecified order, and then all
the initialization forms are evaluated, also in unspecified order.
In this final example, the data structure to be dumped has no special properties and an equivalent structure can be reconstructed simply by reconstructing the slots’ contents.
(defstruct my-struct a b c)
(defmethod make-load-form ((s my-struct))
(make-load-form-saving-slots s))
This is easy to code using
make-load-form-saving-slots
.
[Function]
make-load-form-saving-slots
object
&optional
slots
This returns two values suitable for return from a
make-load-form
method. The first argument is the object.
The optional second argument is a list of the names of slots to
preserve; it defaults to all of the local slots.
make-load-form-saving-slots
returns forms that construct
an equivalent object using make-instance
and
setf
of slot-value
for slots with values, or
slot-makunbound
for slots without values, or other
functions of equivalent effect.
Because make-load-form-saving-slots
returns two values,
it can deal with circular structures; it works for any object of
metaclass standard-class
or structure-class
.
Whether the result is useful depends on whether the object’s type and
slot contents fully capture an application’s idea of the object’s
state.
Next: Accessing Directories
Up: File System Interface
Previous: RenamingDeleting,
and
AI.Repository@cs.cmu.edu