Когда STRUCTURE-OBJECTs (и некоторые другие типы объектов) появляются как литеральные константные объекты в коде, обрабатываемом 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 не будет задействован.)
person
Community
schedule
07.12.2008