LINUX.ORG.RU

Помогите разобраться с мультиметодами.

 , , , ,


1

3

Я пытаюсь найти пример, по которому можно четко понять преимущество мультиметодов над одиночной диспетчеризацией и message-passing. Оговорюсь, на всякий случай, что это преимущество я не пытаюсь отрицать, просто до меня пока не доходит.

Сначала пытался понять пример с астероидами и кораблями с википедии.

https://ru.wikipedia.org/wiki/Мультиметод#Common_Lisp

Но,по этому примеру невозможно ничего понять, потому-что, на мой взгляд, задача сформулированна неверно. Во-первых, столкновение это событие. Причем здесь функция collide — абсолютно непонятно. Функция может быть инициатором события, а нам в данной задаче нужна реакция на событие. Во-вторых, когда сталкиваются 2 объекта, вопрос о том кто с кем столкнулся не имеет никакого смысла, тут невозможно выделить пассивную и активную сторону, активной стороной являются обстоятельства, которые привели к столкновению. Поэтому, пример, мягко говоря синтетический, и ничего не проясняет. Ну, и кроме того, в том виде он тривиально пишется и в «традиционном» стиле.

Затем я пытался понять преимущество мультиметодов на этом вот примере из PCL

http://spline-online.tk/wiki/doku.php?id=pcl:chapter16#defmethod

С банковским «приложением», но снова ничего не понял. Все что там показывается, без мультиметодов, по моему, будет не хуже, и не сложней.

Очень хотелось бы увидеть какое-то объяснение, или пример, где преимущество мультиметодов было бы очевидно и однозначно. К сожалению, я таких примеров пока не нашел.

Подскажите пожалуйста, где можно такое найти, или, если не трудно, приведите пример, демонстрирующий преимущество.



Последнее исправление: asteroidcollide (всего исправлений: 2)
Ответ на: комментарий от monk

К тому же, могут быть случаи, когда именно такое поведение и нужно. Изменение классов в рантайме — это вообще одна из наиболее мощных фич динамического ООП с первоклассными типами.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

нет инкапсуляции, все зависит исключительно от глобального объекта

Не понял, что зависит?

преимущество такого подхода, и область его применения — эти темы по-прежнему не раскрыты

Так ты же сам только что изобрёл мультиметоды на Io для решения такой задачи. Любая задача, где необходимо уточнять метод не только по иерархии его владельца, но и по иерархии(-ям) его аргументов.

Фактически, любая задача, где применим Visitor.

monk ★★★★★
()
Ответ на: комментарий от no-such-file

1.Менеджер столкновения.

Процедурный подход. В этом случае объекты (конкретные корабль, астероид) представляют собой «безжизненные» структуры данных с методами модификации внутреннего состояния извне, без собственного поведения. Тогда зачем тут ООП? Объявляйте структуры.

2.Просто пишем мультиметод на каждый нужный вариант.

Объект события столкновения может передаваться по цепочке (по графу) участвующих в столкновении объектов для: 1) обеспечения их осведомлённости о произошедшем событии и 2) инициации с определённого поведения на это событие. В ООП нужен особый механизм диспетчеризации объекта события столкновения между объектами, который бы предотвращал множественный обмен объектами событий между взаимодействующими объектами и гарантировал, что объект события столкновения придёт только к тем объектам, которые действительно столкнулись, не множась через них. Я правильно понял суть мультиметодов?

iZEN ★★★★★
()
Ответ на: комментарий от monk

Не понял, что зависит?

В обычном ООП смысле. Объект инкапсулирует доступ к памяти, типа, одно дело, когда два процесса пишут и читают в кусок памяти — Account, получается бяка, а когда Account у нас актор, он инкапсулирует операции со своей памятью, никаких казусов не возникает, друге акторы шлют ему сообщения. В процедурной парадигме фактически нет множества объектов, там один глобальный объект, пассивные структуры данных и процедуры, соответственно, нет инкапсуляции, и определение мультиметода с помощью глобального идентификатора — из той же оперы.

где применим Visitor.

Говорят, что визитор решает задачи типа, модификации поведения класса без изменения в его реализации. Но я не понимаю, почему это нельзя решить тупо с помощью коллбека, или банальной передачей объекта/класса в модифицирующую его функцию. В целом, похоже, что этот паттерн был разработан не для проектирования, а для преодоления ограничений конкретных языков

asteroidcollide
() автор топика
Ответ на: комментарий от iZEN

Объект события столкновения может передаваться по цепочке (по графу) участвующих в столкновении объектов для: 1) обеспечения их осведомлённости о произошедшем событии и 2) инициации с определённого поведения на это событие. В ООП нужен особый механизм диспетчеризации объекта события столкновения между объектами, который бы предотвращал множественный обмен объектами событий между взаимодействующими объектами и гарантировал, что объект события столкновения придёт только к тем объектам, которые действительно столкнулись, не множась через них. Я правильно понял суть мультиметодов?

по-поему, мультиметоды в том смысле как раз сосут, потому что они предполагают атомарную синхронную реакцию всех заинтересованных участников. Это в общем случае не годно для моделирования процесов реального мира. Банальный пример: молния, затем гром, «подписчики» грома получают звук в зависимости от их местоположения, не одновременно.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

они предполагают атомарную синхронную реакцию всех заинтересованных участников.

«Атомарная синхронная реакция» и «одновременность реакций всех столкнувшихся» здесь синонимы?

Банальный пример: молния, затем гром, «подписчики» грома получают звук в зависимости от их местоположения, не одновременно.

Событие «молния», которое требует почти мгновенной реакции на световой сигнал объектов в ближайшей округе, порождает событие «гром», которое имеет пространственно-временные (продвижение ударной волны по местности происходит со скоростью звука) и физические (величина громкости на удалении от породившей его молнии) свойства. Так что тут модель взаимодействия сложнее, но ничто не мешает детализировать до нужного уровня.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

представляют собой «безжизненные» структуры данных с методами модификации внутреннего состояния извне

Не извне, а из мультиметода, который внезапно да, не принадлежит конкретным объектам или классам.

Объект события столкновения

Не нужен.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Объект события столкновения

Не нужен.

А что вместо него, факт вызова метода?

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

«Атомарная синхронная реакция» и «одновременность реакций всех столкнувшихся» здесь синонимы?

Да

asteroidcollide
() автор топика
Ответ на: комментарий от iZEN

Точней говоря, там реакции будут, строго говоря не одновременные, но строго последовательные(просто функция исполняется синхронно). Но это в данном случае не особо важно

asteroidcollide
() автор топика
Ответ на: комментарий от no-such-file

Не нужен

Нужен, потому что кто-то должен вызвать твои мультиметоды в ответ на событие. Он может быть подковерным, но он все равно есть, и мультиметоды его не отменяют

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

Среда моделирования могла бы порождать объект события в момент возникновения со списком объектов, которые его ожидают. Далее, объект события может последовательно (или параллельно, если такое возможно - ничего не мешает) оповестить всех заинтересованных объектов в этом списке (вызвать метод каждого «слушателя», в котором передаёт себя в качестве параметров), тем самым вызвав их реакцию на это событие.

В чём несоответствие этого механизма (замены) «мультиметодов»? Здесь в принципе объекты не знают друг о друге.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 4)
Ответ на: комментарий от iZEN

Несоответствие проявится именно тогда когда нам нужны реакции на события, зависимые от каких то других факторов. К примеру, Вася посылает письмо Маше и Свете, но у Светы почтовое отделение плохо работало, И поэтому Вася женился на Маше, а могло быть наоборот.

А то что Вы говорите, по-моему, все это решается обычным паттерном Observer, тут мультиметоды тоже не нужны, только лишнее усложнение.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

Несоответствие проявится именно тогда когда нам нужны реакции на события, зависимые от каких то других факторов.

Информация об этих факторах в каком месте доступна? В том и нужно обрабатывать.

А то что Вы говорите, по-моему, все это решается обычным паттерном Observer

Да. А что, надо как-то по-другому?

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Да. А что, надо как-то по-другому?

Ну так смысл топика в том, чтобы выяснить, в каких случаях применение мультиметодов необходимо, или имеет явное преимущество, потому что они преподносятся как серебрянная пуля. Про визитор ясно, что если есть мультиметоды, то визитор не нужен, эта мантра повсюду. Но этого слишком мало, к тому же польза от самого визитора сомнительна, он больше похож на костыль.

asteroidcollide
() автор топика
Ответ на: комментарий от iZEN

В том и нужно обрабатывать.

Не обязательно в том месте. Допустим, с датчика уровня масла на контроллер приходит информация о низком уровне, а контроллер его пересылает на прибор, или еще куда то, где она обрабатывается.

asteroidcollide
() автор топика
Ответ на: комментарий от iZEN

тем самым вызвав их реакцию на это событие.

Ок, теперь камень должен обработать столкновение, но реакция должна зависить от типа объекта с которым столкнулись. Делать switch по типу?

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

В каких то случаях свитч по типу будет самым простым и подходящим решением. Мультидиспетчирезация выигрывает тут только в том, что можно менять обработчики в рантайме. Но даже для таких случаев можно написать частное, более эффективное и простое решение.

И, похоже на то, что на этом случае реальная польза от мультидиспетчеризации заканчивается. А между тем, она чаще всего позиционируется как полная альтернатива сообщениям, «альтернативное ООП», отличное от классического, что представляется полнейшей ахинеей. В этом топике мы, таки расставили точки над i.

asteroidcollide
() автор топика
Ответ на: комментарий от no-such-file

Не тип объекта, а реальные объекты, ссылки на которые инкапсулированы в объекте-событии, передаваемом средой моделирования камню. Камень может прочесть этот список и решить, как себя повести (дать свою реакцию на событие) в зависимости от объекта столкновения с конкретными свойствами. Информация о типе объекта (к какому классу относится объект) здесь лишняя. Объекты должны реализовать лишь один интерфейс для взаимодействия друг с другом из двух методов: 1) чтобы узнать конкретные свойства (массу и объём, например) и, если необходимо, 2) чтобы изменить поведение наглеца, посмевшего столкнуться (вектор скорости и плотность, например). Так можно смоделировать упругие соударения и разрушающие взаимодействия физических тел, действующих друг на друга.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 2)
Ответ на: комментарий от iZEN

в зависимости от объекта столкновения с конкретными свойствами

бла бла бла, а в итоге

if (obj->isRock()) { this->doRockCollide(); }
if (obj->isRocket()) { this->doRocketCollide(); }

Офигенное ООП, что ты там трындел про процедурный подход?

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)
Ответ на: комментарий от asteroidcollide

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

Не-не-не. Мультидиспетчеризация как и всё ООП не про рантайм, а про наследование.

Вот сделал ты в камне switch с вариантами земля, камень, дерево. А тут вдруг от дерева отнаследовался баобаб, у которого другая реакция на соударение. И разработчику баобаба надо разыскивать разработчика камня, чтобы переделать внутренности этого самого камня. Никакого ООП и инкапсуляции.

А мультиметоды рулят перед посетителем в том, что на мультиметодах я легко могу сделать что-то вроде соударение(камень, земля, лето), соударение(камень, вода, лето), соударение(дерево, земля, зима), ... А на шаблоне Посетитель я заколебусь двойной диспатч руками делать.

monk ★★★★★
()
Ответ на: комментарий от no-such-file

Ты забыл про интерфейсы в качестве универсальных спецификаторов доступа к объектам. Тогда не надо будет плодить switch для определения типа объекта (к какому классу принадлежит объект), чтобы вызвать его метод - достаточно в каждом объекте имплементировать интерфейс с одной сигнатурой и вызывать метод объекта (неважно какого) одной командой.

https://wikipedia.org/wiki/Интерфейс_(объектно-ориентированное_программирование)

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 1)
Ответ на: комментарий от monk

Мультиметоды реализуются не только на основе определения типа:

Глава 7. Мультиметоды

Выше мы говорили о протоколах: они вводят часто используемую, но ограниченную форму полиморфизма - с выбором метода на основе типа. В этой главе мы исследуем мультиметоды (multimethods), позволяющие выбирать реализацию не только на основе типа аргумента, но на некоторых других показателях, никак не связанных с типами. То есть выбор той или иной реализации мультиметода может быть организован, как функция от любого свойства аргумента, без каких-либо привелегий одних перед другими. Кроме того, мультиметоды поддерживают произвольные иерархии и предоставляют различные способы устранения неоднозначностей при множественном наследовании.
«Программирование на Clojure. Практика применения Lisp в мире Java», Кристоф Гранд, Брайан Карпер, Чаз Эмерик, 2013г.

iZEN ★★★★★
()
Последнее исправление: iZEN (всего исправлений: 1)
Ответ на: комментарий от iZEN

достаточно в каждом объекте имплементировать интерфейс

Ты слепой? Мне нужно в ЭТОМ объекте делать что-то в зависимости от типа ДРУГОГО объекта. А ну да, можно сделать визитор obj->doCollide(this) и метод другого объекта будет менять состояние этого объекта в зависимости от своего типа. Офигенное ООП - теперь объекты лезут в потроха друг-друга и всё зависит от всего, если нужно добавить какой-то новый класс нужно править все классы, ведь нужно везде добавить реализацию doCollide(newSuperRocket o)

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Кстати, да, интересный вопрос возник. Ведь визитор не завязан напрямую на типах.

А лисп может диспетчеризовать по другим принципам? Не основываясь на типах объектов?

asteroidcollide
() автор топика
Ответ на: комментарий от no-such-file

Офигенное ООП

ведь нужно везде добавить реализацию doCollide(newSuperRocket o)

Именно! Поэтому Visitor считается антипаттерном. Но это ни сколько не умаляет ООП. Его придумали люди, а не сам он появился вследствие технологии.

iZEN ★★★★★
()
Ответ на: комментарий от iZEN

Но это ни сколько не умаляет ООП

Кто бы спорил. Особенно ООП с мультиметодами.

no-such-file ★★★★★
()
Ответ на: комментарий от iZEN

позволяющие выбирать реализацию не только на основе типа аргумента, но на некоторых других показателях

Это в кложуре. Там функция диспатчинга задаётся явно. В clos тоже можно, но это не тривиально. Видел одну работу, где добавили в clos возможность использовать вместо типа параметра метода произвольный предикат. Но это чисто академические извращения. В той же кложуре все используют (defmulti foo class) и не выёживаются.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

Это в кложуре. Там функция диспатчинга задаётся явно. В clos тоже можно, но это не тривиально.

В том виде, как в кложуре, тривиально

(defun multi (a b c)
  (real-multi (dispatch1 a) (dispatch2 b) (dispatch3 c)))

(defgeneric real-multi)

Видел одну работу, где добавили в clos возможность использовать вместо типа параметра метода произвольный предикат. Но это чисто академические извращения.

Я для Scheme такое делал https://github.com/Kalimehtar/gls. Даже кто-то его использует.

monk ★★★★★
()
Ответ на: комментарий от monk

А как будет выглядеть вот такой визитор на мультиметодах?

A := Object clone do(
    a := 0
    accept := method(visitor, visitor doA(self))
)
B := Object clone do(
    b := 0
    accept := method(visitor, visitor doB(self))
)

Visitor := Object clone do(
   doA := method(acceptor, acceptor a = acceptor a + 1)
   doB := method(acceptor, acceptor b = acceptor b + 1)
)

a := A clone
b := B clone
visitor := Visitor clone

list(a, b) foreach(acceptor, acceptor accept(visitor)) 

writeln(a a, b b) #>>>>11
или так нельзя?

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

А как будет выглядеть вот такой визитор на мультиметодах?

(defclass a () ((a :accessor a :initform 0)))
(defclass b () ((b :accessor b :initform 0)))
(defmethod do1 ((a a))  ;; do1, так как do -- встроенная форма
  (setf (a a) (+ (a a) 1))) 
(defmethod do1 ((b b))
  (setf (b b) (+ (b b) 1))) 

(let ((a (make-instance 'a))
      (b (make-instance 'b)))
  (dolist (x (list a b)) (do1 x))
  (format t "~a~a" (a a) (b b)))
monk ★★★★★
()
Ответ на: комментарий от monk

Ну или

(defclass a () ((a :accessor a :initform 0)))
(defclass b () ((b :accessor b :initform 0)))
(defmethod accept ((a a) v) (do-a v a))
(defmethod accept ((b b) v) (do-b v b))
(defclass visitor () ())
(defmethod do-a ((v visitor) a) (setf (a a) (+ (a a) 1)))
(defmethod do-b ((v visitor) b) (setf (b b) (+ (b b) 1)))
(let ((a (make-instance 'a))
      (b (make-instance 'b))
      (visitor (make-instance 'visitor)))
  (dolist (x (list a b)) (accept x visitor))
  (format t "~a~a" (a a) (b b)))

monk ★★★★★
()
Ответ на: комментарий от monk

Или

(defclass a () ((a :accessor a :initform 0)))
(defclass b () ((b :accessor b :initform 0)))
(defun accept (a v) (do1 v a))
(defclass visitor () ())
(defmethod do1 ((v visitor) (a a)) (setf (a a) (+ (a a) 1)))
(defmethod do1 ((v visitor) (b b)) (setf (b b) (+ (b b) 1)))
(let ((a (make-instance 'a))
      (b (make-instance 'b))
      (visitor (make-instance 'visitor)))
  (dolist (x (list a b)) (accept x visitor))
  (format t "~a~a" (a a) (b b)))
monk ★★★★★
()
Ответ на: комментарий от monk

Не уверен, что это тоже самое. У вас В определении методов везде жестко прописаны типы, разве нет? То есть, тут диспетчеризация по типам, опять же, а в моем примере, никакой зависимости от типа нет, визитор посетит любой тип с подходящим интерфейсом

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

Не уверен, что это тоже самое. У вас В определении методов везде жестко прописаны типы, разве нет?

Здесь использовалось неявное предположение, что doA имеет только класс A и его потомки, а doB — класс B.

Я потому три версии и сделал. Вторая — полный аналог без дополнительных допущений.

monk ★★★★★
()
Ответ на: комментарий от monk

. Вторая — полный аналог без дополнительных допущений.

(defmethod accept ((a a) v) (do-a v a))
(defmethod accept ((b b) v) (do-b v b))
(defmethod do-a ((v visitor) a) (setf (a a) (+ (a a) 1)))
(defmethod do-b ((v visitor) b) (setf (b b) (+ (b b) 1)))

У вас везде в определениях мультиметодов прописаны типы. Это не аналог

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

У вас везде в определениях мультиметодов прописаны типы.

У вас тоже.

A := Object clone do(
    a := 0
    accept := method(visitor, visitor doA(self))
)
Этот accept вызывается только если получатель сообщения имеет тип A.

Тип второго параметра мультиметода (который аналогичен первому параметру метода) у меня не указан.

(defmethod accept ((a a) v) (do-a v a))

Это не аналог

Полный аналог. Или придумайте тест с отличающимся поведением.

monk ★★★★★
()
Ответ на: комментарий от monk

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

asteroidcollide
() автор топика
Ответ на: комментарий от monk

Придумал пример, который более внятно выражает мою мысль


SpaceObject := Object clone do(
     name ::= nil
     collide := method(
       call evalArgs foreach(visitor, visitor  multyMethod(self))
     )
     multyMethod ::= method(spaceObject, writeln(spaceObject name ..  " collide with " .. self name)) // default 
)


Foo := SpaceObject clone setName("asteroid")
Bar := SpaceObject clone setName("spaceship")
Baz := SpaceObject clone setName("planet") setMultyMethod(
  method(spaceObject, writeln("just another behavor for " .. spaceObject name .. " with planet"))
)

foo := Foo clone
bar := Bar clone
baz := Baz clone


foo collide(bar, baz)
bar collide(foo, baz)
baz collide(foo, bar)



#>>>> asteroid collide with spaceship
#>>>> just another behavor for asteroid with planet
#>>>> spaceship collide with asteroid
#>>>> just another behavor for spaceship with planet
#>>>> planet collide with asteroid
#>>>> planet collide with spaceship

Диспетчеризация идет не по типу, а по слоту «name». И вопрос не в том, можно ли на лиспе реализовать такое поведение, а в том, можно ли это сделать только и исключительно мультиметодами.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

Но это определяется не типом, а его интерфейсом

Тип и интерфейс отличаются только синтаксически.

monk ★★★★★
()
Ответ на: комментарий от monk

В нормальном языке тип является частным случаем объекта. Под интерфейсом я подразумевал понятие в широком смысле — совокупность сообщений, на которые он отвечает, иными словами, поддерживаемый протокол. Это совершенно разные вещи. Как объект и язык объекта.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

Диспетчеризация идет не по типу, а по слоту «name».

Вот это не понял. Насколько я вижу, диспетчеризация идёт по классу («just another behavor for spaceship with planet» добавляется наследникам Baz, а не всем, где name = «planet»).

(defun collide (a &rest args)
  (dolist (x args) (multi a x)))

(defmethod multi (a b)
  (format t "~a collide with ~a~%" (name a) (name b)))

(defclass foo () ((name :initform "asteroid" :reader name)))
(defclass bar () ((name :initform "spaceship" :reader name)))
(defclass baz () ((name :initform "planet" :reader name)))

(defmethod multi (a (b baz))
  (format t "just another behavor for ~a with ~a~%" (name a) (name b)))

(let ((foo (make-instance 'foo))
      (bar (make-instance 'bar))
      (baz (make-instance 'baz)))
  (collide foo bar baz)
  (collide bar foo baz)
  (collide baz foo bar))
monk ★★★★★
()
Ответ на: комментарий от asteroidcollide

Под интерфейсом я подразумевал понятие в широком смысле — совокупность сообщений, на которые он отвечает, иными словами, поддерживаемый протокол.

Вообще-то это и есть тип. По [ur=https://ru.wikipedia.org/wiki/Тип_данных]определению тип — множество объектов и операций над этими объектами.

Если считаешь, что они разные, можешь привести на Io пример, где meth1 будет вызываться на основании типа, а meth2 на основании интерфейса?

monk ★★★★★
()
Ответ на: комментарий от monk

Кстати, раз уж пошли многоаргументные функции. Как будешь на Io писать такое:

;; библиотека с протоколом столкновений 3-х объектов
(defclass asteroid () ())
(defclass spaceship () ())

(defmethod collide ((a asteroid) (b spaceship) (c spaceship))
  (print "Two spaceships evaded asteroid"))

(defmethod collide ((a spaceship) (b asteroid) (c spaceship))
  (print "Spaceship hit asteroid and another spaceship"))

;;; используем библиотеку, добавляем planet, код библиотеки про planet знать не должен
(defclass planet () ())
(defmethod collide ((a planet) (b asteroid) (c spaceship))
  (print "Planet hit asteroid and spaceship"))
(defmethod collide ((a asteroid) (b planet) c)
  (print "Asteroid hit planet and annihilated"))
(defmethod collide ((a spaceship) (b planet) (c asteroid))
  (print "Spaceship firead planet and asteroid"))

(let ((planet (make-instance 'planet ))
      (asteroid (make-instance 'asteroid))
      (spaceship (make-instance 'spaceship)))
  (collide asteroid spaceship spaceship)
  (collide spaceship asteroid asteroid)
  (collide planet asteroid spaceship)
  (collide asteroid planet splaceship)
  (collide spaceship planet asteroid))

Визитора тут уже не хватит.

monk ★★★★★
()
Ответ на: комментарий от monk

определению тип — множество объектов и операций над этими объектами.

это определение не годится для нормального ООП, где типы — первоклассные объекты. Это какая то математическая невнятная туфта, короче. объект, тип — это все акторы, а их интерфейс — это их язык.

asteroidcollide
() автор топика
Ответ на: комментарий от asteroidcollide

всем

Quux := SpaceObject clone setName("planet")

quux:= Quux clone

foo collide(bar, quux)

даст

#>>>> asteroid collide with spaceship
#>>>> just another behavor for asteroid with planet
?

monk ★★★★★
()
Ответ на: комментарий от asteroidcollide

это определение не годится для нормального ООП, где типы — первоклассные объекты

Почему? Первоклассность позволяет из типа получить список операций, позволяет проверить значение на соответствие типу, который хранится в переменной и т.д.

объект, тип — это все акторы, а их интерфейс — это их язык.

Можешь привести два метода, один чтобы определялся типом. второй — интерфейсом? А то я никак понять не могу.

monk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.