среда, 26 ноября 2014 г.

[prog.flame] Вынесу из комментариев про ООП

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

ООП -- это сложная тема. На базе принципов она более-менее понятна, а вот когда опускаешься к деталям, обнаруживается большое количество белых пятен. Ситуация усугубляется еще и тем, что из широкоизвестных ОО языков чисто ОО языками являются всего два -- Java и Eiffel. Все остальные из тех, что приходят на ум, гибридные. Даже SmallTalk и Ruby несут в себе следы функциональщины (что не удивительно, т.к. Алан Кей сам признавался, что Lisp на него очень повлиял во время работы над SmallTalk-ом). Поэтому, скажем, при работе на C++ или Ruby можно не сталкиваться с ОО-граблями потому, что в этих языках они обходятся совсем другими способами. Тогда как в Java их, что называется, не обойти и не объехать.

Тут выше в комментариях дали ссылку на фрагмент книги о Haskell-е. Там хороший пример приведен. Когда класс требует наличия operator<, а тип, который имеет такой метод, автоматически становится принадлежащим этому классу. В C++ такая штука присутствует в чистом виде при работе с шаблонами. В Ruby/Python/SmallTalk -- благодаря динамической утиной типизации.

А вот статически-типизированных ОО-языках как это выражать? Там ведь очень редко где поддерживается структурная эквивалентность (т.е. тот же duck typing, но статический). Простейший вариант, который и был реализован в Java -- это наследование: либо реализации (поэтому в базовом Object-е собрано столько всякого хлама), либо интерфесов. Но при этом интерфейсы не могут иметь реализаций методов. Т.е. в Java (по крайней мере той, с которой я когда-то работал) нельзя сделать интерфейс Comparable с одним абстрактным методом lessThan и неабстрактными equal, lessEqual, greaterThan, greaterEqual, notEqual, которые были бы реализованы на основе единственного абстрактного lessThan. Вот поэтому Java, хоть и является чистым ОО языком, но это ублюдочно убогий ОО язык.

Тогда как второй чистый ОО-язык, да еще и статически-типизированный, Eiffel, эти проблемы решает на раз за счет того, что в нем есть нормальное множественное наследование. Т.е. нарезать в Eiffel-е "интерфейсов" вроде Comparable можно множество, и не страшно если в каждом будет всего один-два абстрактных метода. Не страшно даже, если методы будут иметь одинаковые названия и разные сигнатуры -- все это решается на уровне подмешивания посредством специальных языковых инструментов. Т.е. авторы Eiffel прекрасно понимали проблемы ООП в статически-типизированном языке и постарались их должным образом решить.

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

Однако, стоит только поработать с более-менее приличной реализацией ООП (скажем в Eiffel) или с ООП в гибридном языке (скажем в C++ или Ruby), так ситуация меняется: да ООП не всегда ложиться на предметную область, ну и не страшно, в языке есть другие инструменты.

Комментариев нет: