TL;DR: Нет. Хорошо спроектированный язык в развитии не нуждается.
Попробую объяснить, что меня, человека с тридцатилетним стажем в разработке, свободно пишущем на более дюжины языков, привело к такому абсурдному — на первый взгляд — выводу.
Более того, ниже я постараюсь уложиться в нескольких абзацев, чтобы рассказать, какие требования лично я предъявляю языку программирования в 2025 году, и почему этому «идеалу» просто некуда «развиваться».
Производительность
Нужна ли современному языку программирования общего назначения производительность? — Нет.
У нас есть си, для микроконтроллеров, зубодробительной арифметики и прочего нишевого использования. Си прекрасно справляется со своей задачей. В 99% современного «приложенческого» кода — узким местом будет криворукость разработчиков, а не производительность языка. Мощности современных процессоров и объемы современной памяти — нивелировали ценность алгоритмических изысков, позволяющих сбрить пару микросекунд. А там, где оно действительно надо — всё еще есть си. Удобных биндингов в си — достаточно. Там, где их по какой-то причине не хватает — можно озаботиться своим микрокомпилятором, как это сделали ребята из команды Nx
— BEAM традиционно был слабоват в числах, ну вот вам компилятор из нативного кода прямо в CUDA, и куда вообще хотите, с JIT’ом и быстрыми арифметичками. Шах и мат.
Более того, виртуальная машина — уже тоже не проблема. У меня много претензий к Гослингу, но это он понял идеально точно (наверняка, посоветовавшись с Гордоном Муром): виртуальная машина не сделает софт настолько медленнее, что от него придется отказаться в пользу компилятора в нативный код.
Производительность в современном приложении зависит только от квалификации разработчика, и удобство использования языка — гораздо важнее, чем нативная компиляция в машинный код.
Повторюсь, пассаж выше (как и все незыблемые правила) — имеет и свои исключения. Но их исчезающе мало. Вспоминается соревнование эликсира с хаскелем и нативным wc
для подсчета пробелов в файле: коробочный параллелизм позволил автору кода практически не отстать ни от реализации на си, ни от реализации на хаскеле. И виртуальная машина не смогла этому помешать.
Поэтому я считаю, что пока речь не заходит о чем-то узкоспециальном, типа алготрейдинга, микроконтроллеров, или еще чего-то с четко очерченными не в пользу разработчика рамками, нарисованными окружающим миром в ареале использования, — о производительности языка сильно заботиться не нужно (иными словами, всё, кроме эзотерики — пойдёт).
Строгая типизация
Нужна ли современному языку программирования общего назначения строгая типизация? — Нет.
Строгая типизация — это то немногое, что функциональщики смогли продать объективистам. Чёрт, да буквально всё в ФП полезнее типов, но нет, купили только это (и отчасти функции высших порядков). Знаете, в чём проблема с типами в языках типа хаскеля? — Они кастрированные, и, как следствие, — очень громоздкие (там что-то с обменом веществ случается, вроде).
Типы могут принести очень много пользы, если они «граждане первого сорта». Ни в одном более-менее распространенном языке, кроме авангарда типа Coq/Rocq, Agda и Lean, и не покидающего стадию пре-альфа Idris, — нет зависимых типов. Строгая типизация без завтипов — детская игрушка. Но это еще не всё: поспешно втаскивая типизацию в языки, где её доселе не было, и где она — чужеродное тело, — втаскиватели понимали, что просто так аверажный разработчик в этот омут не полезет, поэтому вкатывание упростили при помощи «типа джокера» —null
/ any
/interface{}
.
В результате разработчик оказывается перед выбором: либо аккуратно выписывать все типы до седьмого колена, как в хаскеле, либо (сроки-то не резиновые) — вот тут пока тиснуть any
и комментарий «// TODO FIXME HEEEEELP
». Понятно, к чему это приводит. Если вы просеиваете муку, и в сите — всего-навсего одна дырка размером с кулак — остальные ячейки могут быть не толще комариного писка, хлеб выйдет комками.
Классы и объекты
Пора отвратить от себя и тех трех с половиной читателей, кто добрался до этого места, не забрызгав слюной праведной ярости свой монитор.
Нужны ли современному языку программирования общего назначения классы и их экземпляры? — Нет.
Не нужны. В экземпляре класса нет ничего такого, что нельзя было бы выразить гораздо более внятно, лаконично и прозрачно — обычным словарём. В конце концов, мы же как-то обходимся джейсоном для передачи «объектов» туда-сюда? Есть очень специальные, навороченные случаи, где простого джейсона не хватает, но язык описания данных, которого хватает, — может быть выражен при помощи джейсона. Вот пример из жизни: мне потребовался обмен данными между монолитом и микросервисом, в котором были нужны sequence и счётные поля (как в XML); я просто написал библиотеку, которая пишет и читает XML в формате JSON на руби и эликсире — и voilà.
При этом в мире не существует данных, которые пока кому-то не удалось бы корректно сериализовать в XML.
Внимание, вопрос: если все данные прекрасно описываются типами данных, разрешенными в джейсоне (строка, число, да/нет, список (массив), мап (dictionary, JSON object), null) — зачем нам лишняя когнитивная нагрузка в виде объектов? Чем экземпляр класса User
лучше кортежа {name, password}
и набора функций, принимающих этот кортеж в качестве параметра вместо this
?
Самое удивительное, что Гвидо был на полшишечки от этого решения, когда придумывал «специальные методы» в питоне (__<name>__
), но потом неугомонный улучшайзинг всё испортил.
Ты чё, пёс, в кодах предлагаешь писать?
Нет, конечно.
Я предлагаю снизить когнитивную нагрузку, а не повысить её. Но, прежде, чем я перейду к тому, чем можно с легкостью заменить и типы, и классы — позвольте перечислить то, без чего я не представляю себе современную разработку.
паттерн-матчинг; везде, где только можно, и еще немного — там, где, казалось бы, нельзя.
примитивы параллелизации; не асинхронности, не конкурентности — параллелизации, чтобы вжух, и оно уже параллельно обрабатывается на всех ядрах всех нод в кластере.
оптимизация хвостовых рекурсивных вызовов; иначе придётся переусложнять (портить) язык циклами.
Всё. Список оказался не слишком-то длинным. При наличии хорошего, продуманного сопоставления с образцом — и типы, и классы, — можно заменить тегами. Вот смотрите {:user, "Pupkin", "12345678"}
— и тип налицо, и функция для работы только с сущностью, помеченной тегом :user
— вырисовывается (def login({:user, name, password}), do: …
).
Бесплатный полиморфизм из коробки, внятные сообщения об ошибках, возможность создавать новые типы (классы) на лету, — всё уже есть.
Нет, серьёзно, просто вдумайтесь: чтобы забить гвоздь — достаточно молотка, микроскоп не нужен!
Хорошие новости
Хорошая (для меня) новость заключается в том, что такой язык существует, и я на нём уже десять лет зарабатываю на еду. Акторная модель, как лучший примитив параллелизации, из известных человечеству, бесподобный паттерн-матчинг и восемь типов без возможности добавления новых — почти сорок лет назад реализовала команда разработчиков эрланга. Вероятнее всего, эти герои (Джо Армстронг и Роберт Вирдинг) не стремились поразить всех своим интеллектом, поэтому вместо интерфейса Option
, реализаций Some
и None
и обязательного для вящего придавливания величием языка unwrap
— предложили в качестве either-монады банальное окортеживание результата, удобное для паттерн-матчинга:
case File.read("file") do
{:ok, content} -> IO.puts(content)
{:error, error} -> IO.puts("Error: #{error}")
end
И так во всём.
Лично мне — такой код и писать и читать — проще и быстрее. И я говорю это, как человек, получавший деньги за создание UML-редактора живого языка программирования, на джаве и хаскеле, почти 25 лет назад. Поработавший с тех пор в нескольких энтерпрайзах. Написавший нативную реализацию числодробилки на расте, чтобы звать её из эрланга (это было до появления Nx
).
Нигде, ни в одном другом языке, у меня не было такой непоколебимой уверенности в том, что код, который я написал, — будет работать так, как написано в спецификации. Даже в тех случаях, которые мне и в страшном сне присниться не могли.
Так а что с развитием?
А куда (зачем) должен развиваться язык, который уже идеально закрывает все потребности? Всякие плюшки, типа быстрой арифметики и компиляции в CUDA — прекрасно добавляются сторонними библиотеками (это не AST, который сторонней библиотекой адекватно не добавить).
Каждый год выходят новые микрооптимизации, документация улучшается (хотя куда уж, казалось бы), вот и всё. И компилятор десятилетней давности легко прожуёт код, написанный вчера, и виртуальная машина его исполнит.
Удачного недоразвития!