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 の参照を 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 は関与しません。)