Недавно на подкасте Spring АйО мы обсуждали новые свитчи в Джаве - с паттерн-матчингом и деструктуризацией. Я тогда ещё выразил мнение, что всё это неправославно, по-зумерски и отход от принципов ООП.
Не от инкапсуляции, полиморфизма и наследования, а вообще от подхода. Новые свитчи будут провоцировать разработчиков писать код по-новому, а не так, как завещали нам наши далёкие предки. С нарушением традиций, норм и устоев. Как учит Кейси Муратори, если вы понимаете о ком я.
Но какие они вообще были эти устои? Каким было ООП, когда всё только началось и чем это отличается от свитчей, до которых мы в конце концов докатились?
Источник ООП
В Джаву ООП пришло из C++. В С++ ООП попало от Бъярны (наверное, это наиболее правильное произношение) Страуструпа, по совместительству автора языка.
А сам Страуструп откуда почерпнул идеи ООП? По его собственному признанию, он взял их из языка программирования Simula, предназначенного для разработки симуляции сложных систем.
Этот язык разработали в норвежской лаборатории Кристен Найгард и Оле-Йохан Даль. В 1967 году между прочим. Наверное, 1967 год это достаточно давно, и можно смело считать, что ООП впервые появилось в Simula?
А вот и нет. При разработке Simula норвежцы использовали идеи Энтони Хоара, также известного, как автора алгоритма быстрой сортировки.
Структуры с дискриминатором
Хоар хотел сделать что-то вроде discriminated unions. То есть структуры, в которых могут быть разные наборы полей, в зависимости от типа. А чтобы разработчик не допустил ошибку и не попробовал получить из структуры поле, которого там нет, в структуре всегда было поле, где был указан её тип. То есть был дискриминатор.
Предполагалось, что разработчик будет писать код как-то вот так. В переменной е тут находится какое-то алгебраическое выражение, которое может быть константой, переменной или чем-то ещё.
consider e when constant then ...
when variable then ...
when pair then ...
Ничего не напоминает? Это же практически один в один switch c паттерн матчингом из новой Джавы!
switch (e) {
case Constant c:
System.out.println(c.value());
break;
case Pair p:
System.out.println(p.left() + ", " + p.right());
break;
case Variable v:
System.out.println(v.value());
break;
}
Для наглядности я добавлю под спойлер пример на джаве, который можно запустить. Только не ищите там большого смысла, я только хотел показать, что по форме это то же самое. Смыслосодержащий код в самом начале, дальше всякие объявления интерфейсов.
Скрытый текст
public class Main {
static void print(Expression e) {
switch (e) {
case Constant c:
System.out.println(c.value());
break;
case Pair p:
System.out.println(p.left() + ", " + p.right());
break;
case Variable v:
System.out.println(v.value());
break;
}
}
public static void main(String[] args) {
print(new ConstantImpl(123));
}
}
sealed interface Expression
permits Constant, Variable, Pair {
}
sealed interface Constant
extends Expression
permits ConstantImpl {
int value();
}
sealed interface Variable
extends Expression
permits VariableImpl {
int value();
void set(int newValue);
}
sealed interface Pair
extends Expression
permits PairImpl {
int left();
int right();
}
record ConstantImpl(int value)
implements Constant {
}
final class VariableImpl
implements Variable {
private int value;
@Override
public int value() {
return value;
}
@Override
public void set(int newValue) {
value = newValue;
}
}
record PairImpl(int left, int right)
implements Pair {
}
То есть ещё в 1966 году, в языке, от которого потом отпочковалось всё известное нам ООП, уже был типобезопасный способ доступа к полям произвольного класса.
И в Simula эта фича тоже была, только за неё отвечало ключевое слово inspect.
А вот в C++ ничего такого уже нет, потому что Бьярна счёл эту возможность вредной и не стал переносить в свой язык. По его мнению она делала код менее модульным, и задачи, которые решались с её помощью, лучше было решать с помощью полиморфизма.
Вот так вот. Энтони Хоар дал, Бьярна Страуструп взял.
switch с паттерн-матчингом – это и есть ортодоксальное ООП!
Я это всё к чему. Как выясняется, идея свитчей по типам структур с последующим доступом к их полям была в ООП с самого начала! Просто она была утеряна при переходе от Simula к C++.
И то, что сейчас делает Джава, это, получается, не отход от изначального ООП, а наоборот, возврат к истокам! Да, Страуструп смог остановить прогресс на 40 лет. Однако жернова истории, хотя и крутятся медленно, в конце концов перемалывают всё.
Посмотрите выступление Кейси Муратори!
Возможно, вам интересно, откуда я знаю такие интересные и захватывающие факты из истории языков программирования. Тут могу вас обрадовать. Всё это и намного больше можно узнать из недавно опубликованного на Ютубе доклада Кейси Муратори. Того самого Кейси Муратори, который давно уже ведёт борьбу против ООП, Solid, а также всего что с ними связано. И, кажется, ведёт по очкам ))) . Держите линк!
P. S.
Идея свитчей по типу, похоже, принадлежит именно Хоару, но вот сама идея типизированных структур из N полей заимствована им у Дагласа Росса в Mit Servomechanisms laboratory, предположительно, в середине пятидесятых годов. Росс даже не называл эти структуры структурами, у него для них было специальное слово - плекс. В этих самых плексах уже были поля, и аналоги виртуальных функций. Только наследования тогда ещё, кажется, не было.
В середине пятидесятых! 70 лет назад!

Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм — Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано