2

Скажем, я пишу следующий фрагмент кода (пожалуйста, простите ошибки, я лисповский новичок, и я не могу запустить CL на этой машине)Этот код CLOS приводит к ошибке выполнения или ошибке времени компиляции в Common Lisp?

(defclass o()()) 
(defclass a (o)()) 
(defclass b (o)()) 
(defgeneric m (x)) 
(defmethod m ((x o)) 
    (print "O") 
) 
(defmethod m ((x a)) 
    (print "A") 
    (call-next-method (make-instance 'a)) 
) 
(defmethod m ((x b)) 
    (print "B") 
    (call-next-method (make-instance 'b)) 
) 

(setq aa (make-instance 'a)) 
(m aa) ;prints A, then O 
(setq bb (make-instance 'b)) 
(m bb) ;prints B, then O 

По моим ожиданиям, он должен напечатать то, что написано в комментариях без каких-либо жалоб.

Что произойдет, если я добавлю следующий код?

(defclass c (a b)()) 
(setq cc (make-instance 'c)) 
(m cc) 

Если я понимаю стандартную комбинацию метода, применяемые методы cc будут отсортированы как (m a), (m b), (m o) и (m b) не будет вызываться call-next-method успешно. Но что на самом деле произойдет? Будет ли жаловаться CL, когда я определяю класс c и скажу, что он лишает цель недействительности цепочки методов для общей функции m? Или будет ошибка времени выполнения?

+0

Я предполагаю, что вы хотели, чтобы первый 'defmethod' специализировал свой аргумент на' o', правильно? – Svante

+0

Вы должны использовать 'make-instance' вместо' allocate-instance', и он принимает символ, поэтому вам нужно процитировать его, когда он будет указан буквально. – Svante

+0

Я писал свой код, используя только спецификацию, поэтому я мог сделать некоторые ошибки. Благодарю. – Alexey

ответ

1

Это должно сигнализировать об ошибке, according to the spec в чрезвычайных ситуациях:

При предоставлении аргументов для вызова-следующий метод, следующее правило должно быть выполнено или ошибка ошибки типа должен быть обозначен знаками: упорядоченный набор применимых методов для измененного набора аргументов для call-next-method должен быть таким же, как и упорядоченный набор применимых методов для исходных аргументов для общей функции. Возможны оптимизации проверки ошибок, но они не должны изменять семантику call-next-method.

Как правильно сказать, порядок топологический класс будет:

  • c
  • a
  • b
  • o

Текстология схема:

o 
/ \ 
a  b 
\ /
    c 

Таким образом, перечень применяемых методов будет:

  • m (a)
  • m (b)
  • m (o)

Так что, если call-next-method не сигнализирует об ошибке, m (a) передаст a в m (b), который не является b.

Этого не должно быть, согласно спецификации, но я считаю, что реализация может решить нарушить это правило по соображениям производительности. Вычислить применимые методы при каждом вызове call-next-method.

PS: Фактически, в зависимости от реализации, call-next-method может проверить, соответствует ли список спецификаторов «верхнего уровня» для новых аргументов таким же, как у оригинала. Для достижения этой цели стандартная вычисленная функция распознавания должна быть более сложной и, возможно, выполнять некоторые побочные действия, которые не могут выполнять нестандартные compute-applicable-methods-using-classes и compute-applicable-methods.

+0

По какой-то причине вызов '(m aa)' привел к «AOO» в SBCL, любая идея, почему «m (o)» вызывается дважды? – Alexey

+0

Это не так. Он печатает '' A '' в 'm (a)', затем печатает '' O ''в' m (o) ', затем REPL печатает результат, который является аргументом' print', который является string '" O "'. Итак, два '' O '', которые вы видите, являются побочным эффектом REPL. Чтобы доказать это, попробуйте вызвать '(progn (m aa) (values))' или добавить '(values)' в качестве последней формы в 'm (o)'. – acelent

1

Это может закончиться неудачей во время компиляции. Скорее всего, это сработает во время выполнения.

Метод m порядок для объекта класса c является:

(c a b o) 

Это ударит a где следующий метод будет вызван на новый экземпляр a. a имеет этот порядок метода для метода m:

(a o) 

Поскольку они имеют различный порядок метода call-next-method должно сигнализировать об ошибке. part of CLHS что пишет об этом:

Предоставляя аргументы призывного следующего метода, следующее правило должно быть выполнено или ошибка ошибки типа должны быть обозначены знаками: заказанный набор применимых методов измененном набор аргументов для call-next-method должен быть таким же, как и упорядоченный набор применимых методов для исходных аргументов для общей функции. Возможны оптимизации проверки ошибок, но они не должны изменить семантику вызова-следующего-метода.

Исправление не должно содержать аргументов call-next-method. После этого вы можете редактировать excpet это напечатанный при вызове (m cc):

"A" 
"B" 
"O" 

В CLISP он сигнализирует об ошибке во время выполнения, а SBCL нет, таким образом, он фактически отрабатывает спецификации в SBCL.

+0

Это не должно прерываться во время компиляции. Он должен завершиться неудачно во время выполнения, но, как вы видели, некоторые реализации не следуют правилу 'call-next-method', когда указаны разные аргументы, поэтому на практике он может не работать во время выполнения. – acelent

+0

@PauloMadeira Невероятно, что это произойдет, но в спецификации нет ничего против этого. То, как я читаю * «Возможны оптимизации проверки ошибок, но они не должны изменять семантику вызова-следующего-метода». *. – Sylwester

+0

Но это касается собственного поведения 'call-next-method', а не поведения компиляции вызовов. – acelent