ООП победило: на нём написано почти всё, чем мы пользуемся каждый день, и почти каждый мейнстримный язык последних тридцати лет – объектный. Тем страннее то, что происходит дальше: языки, которые придумывают сейчас, от части его механизмов отказываются сознательно – где-то от наследования, где-то от классов целиком.
Получается парадокс: индустрия пишет на ООП и одновременно от него отказывается. Значит, что-то в парадигме решало задачу 70-х, а не сегодняшнюю. Что именно оказалось лишним и почему – постараемся получить ответ на этот вопрос в рамках курса.
Кто и от чего отказался
Спорить об ООП вообще бессмысленно – смотреть надо на конкретные языки. Вот четыре, и все четыре отказались от разного. Переключайте вкладки:
Go – ни классов, ни наследования, ни иерархии типов. Остались структуры, методы и интерфейсы, причём интерфейс реализуется молча: тип просто имеет нужные методы, объявлять родство не нужно. Вместо «этот класс – потомок того» здесь «этот тип умеет то, что нужно вызывающему».
Rust – классов нет, наследования нет принципиально. Данные лежат в структуре, поведение – в отдельном блоке impl, общее поведение описывают трейты. То, что в ООП делают через базовый класс, здесь делают через «умеет вот это» – и проверяет это компилятор.
Zig – объектных механизмов нет вовсе: структуры и функции, всё явно. Язык сознательно не даёт спрятать за вызовом ни аллокацию, ни диспетчеризацию. Инкапсуляция тут не про приватные поля, а про то, что происходящее видно в коде целиком.
Elixir – данные неизменяемы, функции отдельно, классов нет и не предполагается. Зато есть процессы, которые обмениваются сообщениями и хранят своё состояние, – ровно то, что Алан Кэй называл объектно-ориентированным программированием. Формально не ООП, по духу – ближе к оригиналу, чем Java.
Каждый из них выбросил своё:
- Go – иерархию типов;
- Rust – наследование;
- Zig – неявность;
- Elixir – изменяемое состояние.
Убрали ли их создатели ООП – или оставили от него самое ценное, выбросив остальное?
Держите этот вопрос в голове до конца курса. К последнему модулю у вас будет достаточно материала, чтобы ответить на него самостоятельно, а не сослаться на чужое мнение.
Что проверять временем
Разбирая каждый следующий механизм, задавайте себе два вопроса:
- какую конкретную проблему он решал в момент появления;
- решается ли эта проблема сегодня как-то иначе.
Часть ответов вас удивит. Наследование, например, в современном коде используют заметно реже, чем предполагали его авторы, – и об этом честно говорят паттерны из последнего модуля.