понедельник, 24 ноября 2014 г.

Удивительные факты о наследовании

Говорят, с тех пор, как в Rust и Go убрали наследование, всех сторонников объектно-ориентированной парадигмы ждёт ад и погибель. Даже вроде бы адекватные блоггеры пишут об этом и советуют забыть про ООП. Код, который приводится в качестве примера, настолько прекрасен, что я не могу его не привести:

trait Animal {
  def word: String
  def talk() { println(this.word) }
}
class Cat extends Animal { def word = "Meow!" }

class Dog extends Animal { def word = "Woof!" }

class JustACat { def meow = "Meow!" }

class HappyCat extends JustACat with Animal {
  def word = meow + " :)"
}

class SadCat extends JustACat with Animal {
  def word = meow + " :("
}
val dog = new Dog()
dog.talk

"Вот по большому счету и все, что нужно знать об АТД и классах типов" сообщает нам автор. "Забудьте об ООП! Используйте АТД и тайпклассы!".

Не имею ничего против trait-ов и языка Scala, но такой пример реализации ООП порадует разве что борцов за права домашних животных. Абсолютно непонятно, какое отношение к реальным программам имеют все эти котики и собачки и как собрать из этих грузок и перегрузок что-то работающее. Вспоминать Майерса или Буча тут не стоит - куда уместней общеизвестная песенка:

Я жму на велике любимом,
Он зовется "Украина"
Но седло от унитаза,
А педаль от пианино.
Все потырили друзья,
В двух местах сломали раму,
Ну и пусть себе смеются,
Металлисты-наркоманы!

Раз уж пошла такая путаница, надо разобраться, какое бывает ООП. Обычно под ним понимают что-то в духе C++/C#/Java - модификаторы public/private/protected, виртуальные функции, наследование, и проч., проч., проч.

Но есть языки наподобие Python, Ruby или PHP - где приватных полей нет вообще, а приватность функций зависит от доброй воли пользователя библиотеки, а типы можно сравнивать через duck typing. При этом наследование в них очень разное: в PHP оно аналогично Java (можно наследовать только от одного класса), Python разрешает множественное наследование, а в Ruby разрешает новомодные подмешивания (впрочем, большинство пользователей про них не в курсе).

Есть, наконец, JavaScript, где наследование через прототип настолько загадочно, что некоторые даже пишут свои обёртки, чтобы заменить его на что-то более привычное. И многие из этих обёрток реализуют и множественное тоже.

Ну и на закуску - есть известные реализации псевдо-ООП на C (вроде тех, что встроены в GTK и WinAPI), есть языки-надстройки вроде Lua, и громадную, ещё с начала 1990-х историю ORM для записи унаследованных объектов в реляционные базы данных.

Как легко заметить, главное в ООП - наследование, а наличие приватных полей и виртуальных функций - дело десятая. Куча народу пишет на JavaScript и не в курсе про его систему наследования, или на Python, а наследуют "как привыкли", с интерфейсами и основным классом.

О чём и было сказано уже в другом блоге, где дискуссия продолжалась: Ситуация усугубляется еще и тем, что из широкоизвестных ОО языков чисто ОО языками являются всего два -- Java и Eiffel.

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

Отправить комментарий