четверг, мая 03, 2007

Мультиметоды

Что такое мультиметод обычно объясняется на одном классическом примере. Вот у нас есть иерархия неких фигур.

struct  Shape            {...};
struct Square : Shape {...};
struct Triangle : Shape {...};

И надо уметь строить их пересечение.
bool    overlap( Square& a, Triangle& b) {...}
bool overlap( Triangle& a, Square& b) {...}
bool overlap( Shape& a, Square& b) {...}
bool overlap( Square& b, Shape& a) {...}

И хочется, чтобы можно было определить функцию вроде
bool    overlap( virtual Shape& a, virtual Shape& b);

При вызове которой автомагически бы выбирался нужный из вариантов overlap.
Формальное определение этого всего: "механизм мультиметодов - механизм вызова виртуальных функций на базе более чем одного объекта".

В своей книге "Дизайн и Эволюция С++" (13.8) Страуструп рассказывает, что очень хотел бы, чтобы мультиметоды были в С++, но вот как-то не сложилось. И в С++09 тоже не сложится, похоже. Предложения по мультиметодам они задвинули куда-то далеко. Вот официальные бумаги по этим предложениям раз и два. (все примеры кода взяты оттуда, кстати)

Мультиметоды можно сделать с использованием RTTI и dynamic_cast'ов. Например вот так: Multiple Dispatch. A new approach using templates and RTTI. Там не все так просто, потому что хочется, чтобы не нужно было делать двойную работу и чтобы не нужно было переписывать куски кода в случае появления новых фигур.

Можно обойтись без RTTI и dynamic_cast'ов. Например как здесь: MultiMethods in C++: Finding a complete solution. Код получается довольно тяжелый. По мне так лучше с RTTI.

Про мультиметоды много и загрузочно можно почитать у Александреску в "Современном проектирование на С++". Глава 11. Она так и называется "Мультиметоды".

Ссылки по теме:
Multiple dispatch - статья в Википедии

4 коммент.:

Ivan Sagalaev комментирует...

Ах вот, что это такое... Как только стала понятна суть, я пошел нашел, как это делается в Питоне, вдруг кому интересно будет. Способ от создателя Питона Five-minute Multimethods in Python.

Вкратце это работает так. В основе все то же определение типа в духе "if это Rectangle and это Circle: вызывать это". Но поскольку это Питон, там можно получить программный доступ не только к типам, но и к имени функции, и к процессу ее "компиляции". Поэтому вместо написания руками здоровенного if нужные функции помечаются некой аннотацией, и функция при создании во-первых регистрируется в map'е со всеми типами своих параметров, а во вторых на ее место в коде подставляется вызывальщик, который будет эти параметры проверять :-).

Вот. Нам не надо ждать, пока язык расширят :-)

lrrr комментирует...

Да чего тут сравнивать с питоном, питон, как динамический язык, в таких вещах на стотыщ очков впереди :)

Я смотрю из языков со статической типизацией multiple dispatch только Nice поддерживает. И то у меня есть очень субъективное такое предчуствие что в таких языках от этого больше граблей чем пользы.

Анонимный комментирует...

Подумалось мне, что можно и без "загрузочного" Александреску ;) обойтись, смотрю
Meyers, "More effective C++" - и точно, Item 31 "Making functions virtual with respect to more than one object."
Разные способы, подробно, но без загруза ;)

Alex Ott комментирует...

Для того, чтобы понять что такое настоящие мультиметоды, надо в первую очередь посмотреть на CLOS - Common Lisp Object System. Вот там можно изменить поведение любого класса не затрагивая его кода напрямую. а пре- и пост- методы, это вообще просто праздник какой-то :-)