Standard Generic Function make-load-form

Syntax:

make-load-form object &optional environment creation-form[, initialization-form]

Method Signatures:

make-load-form (object standard-object) &optional environment

make-load-form (object structure-object) &optional environment

make-load-form (object condition) &optional environment

make-load-form (object class) &optional environment

Arguments and Values:

object—an object.

Barrett: Moved up from end, so arguments first, then values.environment—an environment object.

creation-form—a form.

initialization-form—a form.

Description:

The generic function make-load-form creates and returns one or two forms, a creation-form and an initialization-form, that enable load to construct an object equivalent to object. Added per item 1 of MAKE-LOAD-FORM-CONFUSION:Environment is an environment object corresponding to the lexical environment in which the forms will be processed.

Added with rewrites per item 1.1 of MAKE-LOAD-FORM-CONFUSION. I had to do some minor fooling with the wording to make it read better using `modern' terminology. -kmp 11-Feb-92 \funref{make-load-form} is called by the \term{file compiler} when \param{object} is referenced as a \term{literal object} in a \term{file} being compiled by \funref{compile-file} if the \term{object} is a \term{generalized instance} of \typeref{standard-object}, \typeref{structure-object}, \typeref{condition}, or any of a (possibly empty) \term{implementation-dependent} list set of other \term{classes}. The \term{file compiler} will only call \funref{make-load-form} once for the \term{same} \term{object} within a single \term{file}. Barrett: Commented out the above, instead referencing the appropriate section describing how the compiler performs constant processing.The file compiler calls make-load-form to process certain classes of literal objects; see Section 3.2.4.4 (Additional Constraints on Externalizable Objects).

Added per item 1.2 of MAKE-LOAD-FORM-CONFUSION:Conforming programs may call make-load-form directly, providing object is a generalized instance of Barrett: Fix dangling reference, now that list has been moved. one of the explicitly named \term{classes} mentioned previously.standard-object, structure-object, or condition.

The creation form is a form that, when evaluated at load time, should return an object that is equivalent to object. 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; see Section 3.2.4 (Literal Objects in Compiled Files). This is the same type of equivalence discussed in issue CONSTANT-COMPILABLE-TYPES.

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. Barrett: Flush "method" -- its the value returned by the function that's being talked about. If the \funref{make-load-form} methodIf make-load-form returns only one value, the initialization form is nil, which has no effect. If object 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.

Both the creation and initialization forms can contain references to \term{objects} of user-defined \term{types} (defined precisely below). Rewritten per item 1.4 of MAKE-LOAD-FORM-CONFUSION:Both the creation-form and the initialization-form may contain references to any externalizable object. However, there must not be any circular dependencies in creation forms. An example of a circular dependency is when 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 would be when 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 reason that initialization forms exist; see the example of circular data structures below.

The creation form for an \term{object} is always evaluated before the initialization form for that \term{object}. When either the creation form or the initialization form references other \term{objects} of user-defined \term{types} that have not been referenced earlier in the \funref{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 \term{object} does not reference any other \term{objects} of user-defined \term{types} that have not been referenced earlier in the \funref{compile-file}, the initialization form is evaluated immediately after the creation form. If a creation or initialization form \f{F} references other \term{objects} of user-defined \term{types} that have not been referenced earlier in the \funref{compile-file}, the creation forms for those other \term{objects} are evaluated before \f{F}, and the initialization forms for those other \term{objects} are also evaluated before \f{F} whenever they do not depend on the \term{object} created or initialized by \f{F}. Where the above rules do not uniquely determine an order of evaluation, which of the possible orders of evaluation is chosen is \term{implementation-dependent}. \idxtext{order of evaluation}\idxtext{evaluation order} Rewritten per item 1.5 of MAKE-LOAD-FORM-CONFUSION:

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 references other objects that have not been referenced earlier in the file being compiled, the compiler ensures that all of the referenced objects have been created before evaluating the referencing form. When the referenced object is of a type which \funref{compile-file}the file compiler processes using make-load-form, this involves evaluating the creation form returned for it. (This is the reason for the prohibition against circular references among creation forms).

Each initialization form is evaluated as soon as possible after its associated creation form, as determined by data flow. If the initialization form for an object does not reference any other objects not referenced earlier in the file and processed by \funref{compile-file}the file compiler using make-load-form, the initialization form is evaluated immediately after the creation form. If a creation or initialization form F does contain references to such objects, 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 these rules do not uniquely determine an order of evaluation between two creation/initialization forms, the order of evaluation is unspecified.

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 implementation-dependent 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, or they might be interpreted by a special-purpose function different from eval. All that is required is that the effect be equivalent to evaluating the forms.

Barrett: Add method descriptions, per make-load-form-confusion.The method specialized on class returns a creation form using the name of the class if the class has a proper name in environment, signaling an error of type error if it does not have a proper name. Evaluation of the creation form uses the name to find the class with that name, as if by calling find-class. If a class with that name has not been defined, then a class may be computed in an implementation-defined manner. If a class cannot be returned as the result of evaluating the creation form, then an error of type error is signaled.

!!! Barrett: MAKE-LOAD-FORM-CONFUSION sayed "... may define additional \term{conforming methods} ...", but we never actually came up with a definition for that term. That whole issue is not currently addressed by the standard, so I'm not going to try to fix it just here.Both conforming implementations and conforming programs may further specialize make-load-form.

Examples:

 (defclass obj ()
    ((x :initarg :x :reader obj-x)
     (y :initarg :y :reader obj-y)
     (dist :accessor obj-dist)))
→ #<STANDARD-CLASS OBJ 250020030>
 (defmethod shared-initialize :after ((self obj) slot-names &rest keys)
   (declare (ignore slot-names keys))
   (unless (slot-boundp self 'dist)
     (setf (obj-dist self)
           (sqrt (+ (expt (obj-x self) 2) (expt (obj-y self) 2))))))
→ #<STANDARD-METHOD SHARED-INITIALIZE (:AFTER) (OBJ T) 26266714>
 (defmethod make-load-form ((self obj) &optional environment)
   (declare (ignore environment))
   ;; Note that this definition only works because X and Y do not
   ;; contain information which refers back to the object itself.
   ;; For a more general solution to this problem, see revised example below.
   `(make-instance ',(class-of self)
                   :x ',(obj-x self) :y ',(obj-y self)))
→ #<STANDARD-METHOD MAKE-LOAD-FORM (OBJ) 26267532>
 (setq obj1 (make-instance 'obj :x 3.0 :y 4.0)) → #<OBJ 26274136>
 (obj-dist obj1) → 5.0
 (make-load-form obj1) → (MAKE-INSTANCE 'OBJ :X '3.0 :Y '4.0)

In the above example, an equivalent instance of obj is reconstructed by using the values of two of its slots. The value of the third slot is derived from those two values.

Another way to write the make-load-form method in that example is to use make-load-form-saving-slots. The code it generates might yield a slightly different result from the make-load-form method shown above, but the operational effect will be the same. For example:

 ;; Redefine method defined above.
 (defmethod make-load-form ((self obj) &optional environment)
    (make-load-form-saving-slots self
                                 :slot-names '(x y)
                                 :environment environment))
→ #<STANDARD-METHOD MAKE-LOAD-FORM (OBJ) 42755655>
 ;; Try MAKE-LOAD-FORM on object created above.
 (make-load-form obj1)
→ (ALLOCATE-INSTANCE '#<STANDARD-CLASS OBJ 250020030>),
    (PROGN
      (SETF (SLOT-VALUE '#<OBJ 26274136> 'X) '3.0)
      (SETF (SLOT-VALUE '#<OBJ 26274136> 'Y) '4.0)
      (INITIALIZE-INSTANCE '#<OBJ 26274136>))

In the following example, instances of 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 existing objects. In this case the programmer has chosen to create a new object if no existing object is found; alternatively an error could have been signaled in that case.

 (defclass my-frob ()
    ((name :initarg :name :reader my-name)))
 (defmethod make-load-form ((self my-frob) &optional environment)
   (declare (ignore environment))
   `(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 parent has a list of its children and each child has a reference back to its parent. If 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 of the creation forms are evaluated, in implementation-dependent order, and then all of the initialization forms are evaluated, also in implementation-dependent order.

 (defclass tree-with-parent () ((parent :accessor tree-parent)
                                (children :initarg :children)))
 (defmethod make-load-form ((x tree-with-parent) &optional environment)
   (declare (ignore environment))
   (values
     ;; creation form
     `(make-instance ',(class-of x) :children ',(slot-value x 'children))
     ;; initialization form
     `(setf (tree-parent ',x) ',(slot-value x 'parent))))

In the following 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) &optional environment)
    (make-load-form-saving-slots s :environment environment))

Affected By:

None.

Exceptional Situations:

\funref{make-load-form} of an \term{object} of \term{metaclass} \typeref{standard-class} or \typeref{structure-class} for which no user-defined \term{method} is applicable signals an error \oftype{error}. It is valid to implement this either by defining default methods on \typeref{standard-object} and \typeref{structure-object} that signal an error \oftype{error} or by having no \term{applicable method} for those \term{classes}. Rewritten per item 1.3 of MAKE-LOAD-FORM-CONFUSION:The methods specialized on standard-object, structure-object, and condition all signal an error of type error.

Barrett: Add per make-load-form-confusion.It is implementation-dependent whether calling make-load-form on a generalized instance of a system class signals an error or returns creation and initialization forms.

See Also:

compile-file, make-load-form-saving-slots, Section 3.2.4.4 (Additional Constraints on Externalizable Objects) Section 3.1 (Evaluation), Section 3.2 (Compilation)

Notes:

The file compiler \funref{compile-file}calls make-load-form in specific circumstances detailed in Section 3.2.4.4 (Additional Constraints on Externalizable Objects). Removed per item 1.2 of MAKE-LOAD-FORM-CONFUSION: It is valid for user programs to call \funref{make-load-form} in other circumstances, providing \param{object}'s \term{metaclass} is neither \typeref{built-in-class} nor a \term{subclass} of \typeref{built-in-class}.

Barrett: Add per make-load-form-confusion.Some implementations may provide facilities for defining new subclasses of classes which are specified as system classes. (Some likely candidates include generic-function, method, and stream). Such implementations should document how the file compiler processes instances of such classes when encountered as literal objects, and should document any relevant methods for make-load-form.