Когда объекты STRUCTURE-OBJECT (и некоторые другие типы объектов) отображаются в виде литералов, константных объектов в коде, обрабатываемом COMPILE-FILE, COMPILE-FILE должен знать, как это устроить, когда загруженный результирующий двоичный файл загружает "эквивалентный" объект создан. Существует много возможных определений «эквивалента»: иногда важно, чтобы компоненты загруженного объекта разделяли структуру с другими объектами, иногда важно, чтобы инициализация происходила определенным образом, а иногда ничего из этого не важно. Чтобы определить, как воссоздать константный объект, COMPILE-FILE вызывает универсальную функцию MAKE-LOAD-FORM; это поведение должно быть описано в любом справочнике или учебнике по CL. (Ссылка или учебное пособие также должны учитывать, что реализация не может определять методы MAKE-LOAD-FORM по умолчанию, которые будут применимы ко всем экземплярам STRUCTURE-CLASS или STANDARD-CLASS, и также следует учитывать, что 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 не будет задействована.)