当 STRUCTURE-OBJECT(和一些其他类型的对象)在 COMPILE-FILE 处理的代码中显示为文字常量对象时,COMPILE-FILE 需要知道如何安排,当加载生成的二进制文件时,“等效”对象被创建。“等效”有许多可能的定义:有时,加载对象的组件与其他对象共享结构很重要,有时初始化以某种方式发生很重要,有时这些都不重要。为了确定如何重新创建常量对象,COMPILE-FILE 调用通用函数 MAKE-LOAD-FORM;此行为应在任何 CL 参考或教程中进行描述。(参考或教程还应注意实现可以'
(defmethod make-load-form ((p point) &optional env)
(declare (ignore env))
(make-load-form-saving-slots p))
请注意,该方法必须在编译时定义,以便 COMPILE-FILE 可以调用它来确定如何保存常量 POINT 对象。
这些都不是特定于 CCL 的。可能的问题是哪些事物是常量、字面对象,哪些事物不是。
在如下代码中:
(defconstant a-point (make-point :x 0 :y 0 :z 200))
(defun return-a-point () a-point)
编译器允许(但不是必需)在函数 RETURN-A-POINT 中用 A-POINT 的值代替对它的引用。(如果编译器这样做,这意味着正在编译的代码中有一个文字/常量 POINT 对象,并且 COMPILE-FILE 需要调用 MAKE-LOAD-FORM 来确定应该如何保存和加载对象;如果编译器不做这个替换,那么在这个例子中不需要调用 MAKE-LOAD-FORM。)
实现是否进行这种替换取决于实现。该规范还没有指定 DEFCONSTANT 形式中的值形式是否在编译时、加载时或两者都计算,并指出必须小心(由用户)确保表达式始终计算为相同的值。
CCL 通常尝试在编译时评估 DEFCONSTANT 值形式,并且相当积极地用命名常量的值替换对它们的引用;在某些情况下,这意味着必须在常量值的类上定义 MAKE-LOAD-FORM 方法。其他实现可能不太愿意对某些类型的对象进行这种替换。这两种策略都是正确的,并且可移植代码不能假设正在遵循哪些策略(尽管许多据称可移植的代码确实会做出这样的假设。)
对 DEFCONSTANT 定义的事物的不同处理似乎是这类事物最可能的原因(对 MAKE-LOAD-FORM 的意外调用,没有人费心去定义)。可以通过以下方式以一种可移植的方式避免其中一些问题:
(defconstant a-point (make-point :x 0 :y 0 :z 200))
(defun return-a-point () (load-time-value (symbol-value 'a-point)))
这将与简单地允许想要这样做的实现(如 CCL 所做的那样)进行常量替换具有类似的效果,但是使用 LOAD-TIME-VALUE 将确保仅在加载时评估常量值(并且不涉及 MAKE-LOAD-FORM 。)