Вызов другого перегруженного метода в Лиспе

Я не мог узнать, возможно ли это, и просто использовал (довольно уродливый) обходной путь.

Предположим, у нас есть структура класса, как показано ниже:

(defclass a () ())
(defclass b (a) ())

и метод:

(defmethod print-object ((a1 a) stream)
 (format stream "instance of A "))

теперь я хочу вызвать print для 'a, а затем print для 'b, предполагая, что существует функция "приведения типов":

(defmethod print-object ((b1 b) stream)
 (prin1 (type-cast b1 'a) stream)
 (format stream "instance of B "))

Мой обходной путь - создать объект типа a внутри объекта печати b, а затем вызвать prin1

(defmethod print-object ((b1 b) stream)
 (let ((a1 (make-instance 'a)))
    (prin1 a1 stream))
 (format stream "instance of B "))

Я пробовал принуждать и получил бесконечный цикл. Я только что понял, что могу попробовать использовать метод поиска и метод вызова (будет ли это работать?). Или я должен попробовать решение с: вокруг?


person AlbusMPiroglu    schedule 26.12.2013    source источник


Ответы (3)


COERCE не работает с объектами CLOS. Вы можете изменить класс экземпляра с помощью CHANGE-CLASS, но обычно это не очень хорошая идея.

CALL-NEXT-METHOD

Вы можете вызвать следующий применимый метод: CALL-NEXT-METHOD. Обратите внимание, что вы не можете вызывать конкретный метод таким образом, только следующий. В большинстве случаев это то, что можно было бы использовать в CLOS. Затем задача состоит в том, чтобы во время определения метода настроить общую функцию таким образом, используя первичные, :around, :before и :after методы, чтобы возникло правильное поведение.

Вызов определенных функций, когда ничего не помогает

Существует эзотерический способ вызова определенного метода:

(funcall (method-function (find-method #'print-object
                                       nil
                                       (list (find-class 'a)
                                             (find-class t))))
         (make-instance 'b)
         t)

В приведенном выше коде функция METHOD-FUNCTION не является частью ANSI Common Lisp, но предоставляется во многих реализациях метаобъектом . Протокол (СС).

person Rainer Joswig    schedule 26.12.2013

Coerce не создает новый объект, потому что b1 уже имеет тип (подтип) a.

Все, что вам нужно, это call-next-method:

(defmethod print-object ((a1 a) stream)
   (format stream "instance of A "))

(defmethod print-object ((b1 b) stream)
   (call-next-method) ; by default same arguments are used: b1 and stream
   (format stream "instance of B "))
person monoid    schedule 26.12.2013
comment
Спасибо за ответ, моноид. Я приму ответ Райнера, поскольку он объясняет, что недостаточно (если у нас есть более реалистичная иерархия классов) вызвать следующий метод, но нам нужно использовать его в сочетании с: вокруг,: до и: после. Мне нужно изучить эти концепции немного больше сейчас :) - person AlbusMPiroglu; 28.12.2013

Следуя примеру блокировки процессов, написанному Соней Кин (Объектно-ориентированное программирование в COMMON LISP: Руководство программиста по CLOS), вы можете использовать метод :after

(defmethod print-object ((a1 a) stream)
  (format stream "instance of A ")) 
(defmethod print-object :after ((b1 b) stream)
  (format stream "instance of B "))

Это даст

CL-USER> (make-instance 'b)
    instance of A instance of B 
person user1597986    schedule 29.12.2013