Читал недавно Бертрана Мейера, наткнулся у него на примерно следующее:
А а
B b
f(a)
f(b)
Такой код плох, потому что нарушает принцип "честности". Читателю сложно понять какая именно f вызывается.
С другой стороны, такой код хорош
[c]
А а
B b
a.m()
b.m()
[c]
До меня не доходит — в чем тут принципиальная разница? Фактически, методы с одинаковыми именами в разных классах (имхо) эквивалентны функциям, перегруженным по одному аргументу. И читатель программы сталкивается с теми же проблемами, что и в случае простых перегруженных функций. А если учесть, что методы могут быть виртуальными, определить, что именно вызывается на самом деле — еще большая проблема.
Здравствуйте, Непомнящий Евгений, Вы писали:
НЕ>Здравствуйте.
НЕ>До меня не доходит — в чем тут принципиальная разница? Фактически, методы с одинаковыми именами в разных классах (имхо) эквивалентны функциям, перегруженным по одному аргументу. И читатель программы сталкивается с теми же проблемами, что и в случае простых перегруженных функций.
Такой сложный уровень перегрузки не очень типичен. Зато указание контекста резко сужает область поиска.
HE> А если учесть, что методы могут быть виртуальными, определить, что именно вызывается на самом деле — еще большая проблема.
Здравствуйте, Непомнящий Евгений, Вы писали:
НЕ>Здравствуйте.
НЕ>Читал недавно Бертрана Мейера, наткнулся у него на примерно следующее: НЕ>
НЕ>А а
НЕ>B b
НЕ>f(a)
НЕ>f(b)
НЕ>
НЕ>Такой код плох, потому что нарушает принцип "честности". Читателю сложно понять какая именно f вызывается.
НЕ>С другой стороны, такой код хорош НЕ>[c] НЕ>А а НЕ>B b НЕ>a.m() НЕ>b.m() НЕ>[c]
НЕ>До меня не доходит — в чем тут принципиальная разница?
Ну чего же тут непонятного?
При первом подходе если ты продал покупателю A и B, не факт, что он закажет f у тебя же. Второй подход в финансовом смысле гораздо заманчивее.
D> D>Ну чего же тут непонятного? D>При первом подходе если ты продал покупателю A и B, не факт, что он закажет f у тебя же. Второй подход в финансовом смысле гораздо заманчивее.
Тогда принцип честности лучше назвать принципом лояльности к бренду.
Здравствуйте, Непомнящий Евгений, Вы писали:
НЕ>... И читатель программы сталкивается с теми же проблемами, что и в случае простых перегруженных функций. А если учесть, что методы могут быть виртуальными, определить, что именно вызывается на самом деле — еще большая проблема.
Согласен. Возможно синтаксис a.f() стоит использовать только в случае виртуальной f, в противном случае — f(a) даже если для этого придется объявить f другом.
Совет использовать f(a) вместо a.f() есть у Саттера, но только для случая, когда можно избежать использования friend. По-моему такое отношение к friend пошло от того, что объявление другом класса действительно плохо. Однако объявление функции другом вовсе не так плохо, функция-друг имеет не больше, а меньше прав чем функция-член. Пора реабилитировать функции-друзья (или функций-друзей, или функции-друзей ).
Здравствуйте, Непомнящий Евгений, Вы писали:
НЕ>Читал недавно Бертрана Мейера, наткнулся у него на примерно следующее:
<>
Бертран Мейер. Объектно-ориентированное конструирование программных систем.
Жирным выделена колокольня, с которой он делает это утверждение.
В ООП-мире весь полиморфизм задвигается в объекты. Разнообразие поведения обусловлено фактическим (ну и, заодно, формальным) типом объекта-подлежащего.
А в ФП-мире нет такого обособления подлежащего перед дополнениями.
В ООП-мире мультиметоды (перегруженные по нескольким аргументам) — это экзотика.
Вот интересно, что Мейер сказал бы про двойную диспетчеризацию?
A a;
B b;
C c;
// мультиметод - то, что мы хотим (и то, что "нечестно", потому что "читателю сложно понять")
f(c,a);
f(c,b);
// всё равно нечестно?
c.f(a);
c.f(b);
// вот так честно, но крайне странно
a.f_(c);
b.f_(c);
// добавляем
D d;
f(a,d);
f(b,d);
// и как теперь честно выкрутиться?
Если язык поддерживает перегрузку (C++, в некотором смысле Haskell), то я не вижу особой разницы — перетаскивать функцию внутрь класса или оставлять снаружи.
Если не поддерживает (Pascal, ML) — то внешняя функция должна иметь разные имена для разных типов, а функция-член это имя выводит неявно по типу подлежащего. Экономия!