当STRUCTURE-OBJECTs(以及其他一些类型的对象)在被COMPILE-FILE处理的代码中以文字、常量对象的形式出现时,COMPILE-FILE需要知道如何安排,当加载生成的二进制文件时,会创建一个“等效”的对象。 “等效”的定义有很多种:有时,加载的对象的组件与其他对象共享结构很重要;有时,初始化以某种方式发生很重要;有时,这些事情都不重要。为了确定如何重新创建常量对象,COMPILE-FILE调用通用函数MAKE-LOAD-FORM;这种行为应该在任何CL参考或教程中描述。(参考或教程还应指出,实现不能定义适用于所有STRUCTURE-CLASS或STANDARD-CLASS实例的默认MAKE-LOAD-FORM方法,并且应注意MAKE-LOAD-FORM-SAVING-SLOTS是用于简化初始化的对象的MAKE-LOAD-FORM方法的方便函数,例如:
(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)
编译器可以(但不是必须)将 A-POINT 的值替换为函数 RETURN-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)。
DEFCONSTANT
表达式中应该调用RETURN-A-POINT
函数吧? - Elias Mårtenson