To load a ﬁle is to read through the ﬁle, evaluating each form in it. Programs are typically stored in ﬁles containing calls to constructs such as defun, defmacro, and defvar, which deﬁne the functions and variables of the program.
Loading a compiled (“fasload”) ﬁle is similar, except that the ﬁle does not contain text but rather pre-digested expressions created by the compiler that can be loaded more quickly.
[Function]load ﬁlename &key :verbose :print :if-does-not-exist
This function loads the ﬁle named by ﬁlename into the Lisp environment. It is assumed that a text (character ﬁle) can be automatically distinguished from an object (binary) ﬁle by some appropriate implementation-dependent means, possibly by the ﬁle type. The defaults for ﬁlename are taken from the variable *default-pathname-defaults*. If the ﬁlename (after the merging in of the defaults) does not explicitly specify a type, and both text and object types of the ﬁle are available in the ﬁle system, load should try to select the more appropriate ﬁle by some implementation-dependent means.
If the ﬁrst 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 ﬁle 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 ﬁle is being loaded, then what is printed may not reﬂect precisely the contents of the source ﬁle, but nevertheless some information will be printed.
The function load rebinds *package* to its current value. If some form in the ﬁle changes the value of *package* during loading, the old value will be restored when the loading is completed. (This was speciﬁed in the ﬁrst edition under the description of *package*; for convenience I now mention it here as well.)
X3J13 voted in March 1988 to specify exactly which streams may be used as pathnames. See section 23.1.6.
X3J13 voted in June 1989 to clarify that supplying a wild pathname as the ﬁlename argument to load has implementation-dependent consequences; load might signal an error, for example, or might load all ﬁles that match the pathname.
X3J13 voted in March 1989 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 ﬁle-loading activity. This allows a portable program to include forms such as
without performing a net global side eﬀect on the loading environment. Such statements allow the remainder of such a ﬁle to be read either as interpreted code or by compile-ﬁle in a syntax determined by an alternative readtable.
X3J13 voted in June 1989 to require that load bind two new variables *load-pathname* and *load-truename*; the dynamic extent of the bindings should encompass all of the ﬁle-loading activity.
This variable provides the default for the :verbose argument to load. Its initial value is implementation-dependent.
X3J13 voted in June 1989 to introduce *load-pathname*; it is initially nil but load binds it to a pathname that represents the ﬁle name given as the ﬁrst argument to load merged with the defaults (see merge-pathname).
X3J13 voted in March 1989 to introduce a facility based on the Object System whereby a user can specify how compile-ﬁle and load must cooperate to reconstruct compile-time constant objects at load time. The protocol is simply this: compile-ﬁle 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-deﬁned metaclass (not a subclass of built-in-class), or any of a possibly empty implementation-deﬁned list of other metaclasses; compile-ﬁle will call make-load-form only once for any given object (as determined by eq) within a single ﬁle. The user-programmability stems from the possibility of user-deﬁned methods for make-load-form. The helper function make-load-form-saving-slots makes it easy to write commonly used versions of such methods.
The ﬁrst 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 deﬁnes a method for make-load-form. This allows the user to program the notion of “similar as a constant” (see section 24.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 eﬀect. 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-deﬁned types (deﬁned 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-deﬁned types that have not been referenced earlier in the compile-ﬁle, 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 ﬂow. If the initialization form for an object does not refer to any other objects of user-deﬁned types that have not been referenced earlier in the compile-ﬁle, the initialization form is evaluated immediately after the creation form. If a creation or initialization form F references other objects of user-deﬁned types that have not been referenced earlier in the compile-ﬁle, 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 unspeciﬁed 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 unspeciﬁed whether load calls eval on the forms or does some other operation that has an equivalent eﬀect. For example, the forms might be translated into diﬀerent 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 diﬀerent from eval. All that is required is that the eﬀect 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-deﬁned method is applicable signals an error. It is valid to implement this either by deﬁning default methods for the classes standard-object and structure-object that signal an error or by having no applicable method for those classes.
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.
This code will fail if either of the ﬁrst two slots of some instance of my-class contains the instance itself. Another way to write the last form in the preceding example is
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.
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.
Suppose make-load-form is called on one object in such a structure. The creation form creates an equivalent object and ﬁlls 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 ﬁlled in. The initialization form ﬁlls 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 unspeciﬁed order, and then all the initialization forms are evaluated, also in unspeciﬁed order.
In this ﬁnal example, the data structure to be dumped has no special properties and an equivalent structure can be reconstructed simply by reconstructing the slots’ contents.
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 ﬁrst 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 eﬀect.
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.