Разработчик веб-приложений и распределённых систем под псевдонимом chreke* убеждён: «малые языки», то есть специализированные языки, созданные для решения конкретных задач, являются будущим программирования. Это убеждение укрепилось в нём после прочтения статьи Габриэллы Гонсалес «Конец истории программирования» и просмотра лекции Алана Кея «Программирование и масштабирование».
Под катом автор объясняет, что подразумевает под «малыми языками», и почему они так важны.
*Обращаем ваше внимание, что позиция автора может не всегда совпадать с мнением МойОфис.
Что представляет собой «малый язык»?
Полагаю, что термин «малый язык» был впервые использован Джоном Бентли в статье под названием «Малые языки», где он дал ему следующее определение:
[...] малый язык ориентирован на конкретную проблемную область и не содержит многие функции, которые есть в обычных языках.
Например, SQL — это язык, предназначенный для описания операций с базами данных. Регулярные выражения — это язык для поиска и замены текста. Dhall — язык для управления конфигурациями и т. д.
У этих языков есть и другие названия: предметно-ориентированные языки (DSL), проблемно-ориентированные языки и т. д. Однако мне больше всего нравится термин «малые языки». Во-первых, потому что термин DSL стал слишком обобщенным и может относиться как к библиотекам с понятным интерфейсом, так и к полноценному языку запросов, например, SQL. Во-вторых, потому что термин «малые языки» подчеркивает их компактность.
Зачем нужны малые языки?
Современное ПО, с точки зрения истории, — инженерия, но это та инженерия, которую осуществляли люди, не знакомые с концепцией арки. Большинство современного программного обеспечения напоминает египетскую пирамиду: миллионы кирпичей, сложенных друг на друга без структурной целостности, созданные лишь благодаря грубой силе и труду тысяч рабов.
В сообществе разработчиков ПО существует серьёзная проблема — чем сложнее становится приложение, тем более объёмным будет его исходный код. Но наша способность понимать большие объёмы кода остается практически неизменной. По данным исследования The Emergence of Big Code («Возникновение большого кода»), проведенного Sourcegraph в 2020 году, большинство респондентов отметили, что размер их кодовой базы приводит к одной или нескольким из следующих проблем:
Трудности с адаптацией новых сотрудников
Сбои в коде из-за недостаточного понимания зависимостей
Управление изменениями в коде становится все сложнее
Более того, приложения, похоже, растут с пугающей скоростью: большинство участников опроса Sourcegraph оценили, что их кодовая база увеличилась в 100-500 раз за последние десять лет. В качестве наглядного примера можно привести ядро Linux, которое в 1992 году состояло из примерно 10 000 строк кода. Спустя двадцать лет, его размер достиг около 30 миллионов строк.
Откуда берется столько кода? Я не думаю, что расширение функциональности может объяснить такой рост его объёма; скорее, это связано с нашим подходом к разработке ПО. Обычно новые функции в программе добавляются поверх уже существующих, как при строительстве пирамиды. Проблема в том, что, как и в случае с пирамидой, каждый новый слой требует больше «кирпичей», чем предыдущий.
Противостояние тенденции
Действительно ли для создания современной операционной системы требуются миллионы строк кода? В 2006 году Алан Кей вместе со своими коллегами из программы STEPS решили опровергнуть следующее предположение:
Наука развивается через взаимосвязь эмпирических исследований и теоретических моделей, поэтому наш первый вопрос как учёных звучит так: если мы создадим работающую модель феномена персональных вычислений, сможет ли она быть упрощена до уровня уравнений Максвелла для всего электромагнитного спектра, или Конституции США, которую можно носить в кармане рубашки, или же она настолько беспорядочна (или действительно сложна), что потребует «3 кубических мили прецедентного права», как в американской правовой системе (или, возможно, в современной практике программного обеспечения)? Ответ, скорее всего, где-то посередине, и было бы очень интересно, если бы он оказался ближе к простому концу, а не к другой огромной хаотичной крайности.
Так что мы задаёмся вопросом: является ли опыт персональных вычислений (учитывая эквивалент операционной системы, приложений и другого вспомогательного программного обеспечения) по своей сути 2 миллиардами строк кода, 200 миллионами, 20 миллионами, 2 миллионами, 200 000, 20 000, 2 000?
— Отчёт о проделанной работе в рамках проекта STEPS, 2007 г., стр. 4–5
Уравнения Максвелла, которые упоминает доктор Кей, — это набор уравнений, описывающих основы электромагнетизма, оптики и электрических цепей. Интересной особенностью этих уравнений является то, что несмотря на их широкий диапазон применения, они настолько компактны, что могут поместиться даже на футболке:
Одной из причин их лаконичности является использование оператора набла (например,∇ ) для описания операций векторного исчисления. Важно понимать, что набла — это не совсем оператор, это скорее сокращение, которое облегчает работу с некоторыми уравнениями в векторном исчислении.
А что если возможно создать аналог оператора набла для программирования? Так же как оператор набла помогает упростить векторное исчисление, не могут ли существовать обозначения, которые помогли бы нам аналогичным образом работать с программами? Этот вопрос был одной из «главных идей», которые стали основой для проекта STEPS:
Мы также уверены, что создание языков, подходящих для решения конкретных задач, упрощает процесс, делает решения более понятными и компактными, что полностью соответствует нашему «активно-математическому» подходу. Эти «проблемно-ориентированные языки» будут создаваться и применяться для решения как крупных, так и мелких задач на различных уровнях абстракции и детализации.
— Отчёт о проделанной работе в рамках проекта STEPS, 2007 г., стр. 6
Суть идеи заключается в том, что когда вы начинаете находить закономерности в своем приложении, вы можете закодировать их при помощи малого языка. Этот язык позволит вам выразить эти закономерности более компактно, чем это возможно с помощью других средств абстракции. Что позволит не только противостоять тенденции к постоянному увеличению размера приложений, но и сократить объём кода в процессе разработки!
Одним из результатов проекта STEPS, который меня особенно впечатлил, стал Nile — малый язык для описания процессов рендеринга и композитинга графики. Целью было использовать Nile для достижения функционального равенства с Cairo — рендерером с открытым исходным кодом, используемым в различных проектах свободного программного обеспечения, общий объём кода которого составляет около 44 000 строк. Аналог на языке Nile в итоге составил всего около 300 строк.
Почему мы не используем языки высокого уровня?
Но Ada не станет той волшебной серебряной пулей, которая победит монстра производительности программного обеспечения. В конце концов, это всего лишь еще один язык высокого уровня, и наибольшая польза от таких языков была получена при первом переходе от непреднамеренных сложностей к более абстрактному представлению пошаговых решений. После устранения этих непреднамеренных сложностей, оставшиеся становятся меньше, и отдача от их устранения, безусловно, будет меньше.
«Но, подождите-ка, — возможно, скажете вы, — почему бы нам просто не создать язык общего назначения более высокого уровня?» Я лично убежден, что мы достигли предела выразительности языков общего назначения. Если есть уровень выше, то как он будет выглядеть? Возьмем, к примеру, Python — он настолько высокоуровневый, что практически выглядит как псевдокод.
Сложность языков общего назначения заключается в том, что вам все же придётся преобразовать вашу задачу в алгоритм и затем представить этот алгоритм на выбранном языке. Языки высокого уровня идеально подходят для описания алгоритмов, но если целью не была реализация алгоритма, то это лишь непреднамеренная сложность.
При написании этого поста мне вспомнилась история о Дональде Кнуте: Кнута попросили продемонстрировать его стиль «грамотного программирования» в колонке «Жемчужины программирования» Джона Бентли; Дуг МакИлрой также был приглашен для критического анализа программы Кнута. Задачей было найти k-ое самое распространённое слово в тексте.
Кнут тщательно написал решение на WEB, его собственной версии языка Pascal для грамотного программирования. Он даже разработал специальную структуру данных для отслеживания количества слов, и все это уложилось в десять страниц кода. МакИлрой высоко оценил мастерство решения Кнута, но сама программа его не особо впечатлила. В рамках своей критики он написал собственное решение на креольском языке, состоящем из shell-скриптов, команд Unix и малых языков:
tr -cs A-Za-z '\n' |
tr A-Z a-z |
sort |
uniq -c |
sort -rn |
sed ${1}q
Этот код может быть не самым понятным для тех, кто не является экспертами по Unix, и возможно МакИлрой согласился бы с этим, так как решил включить аннотированную версию. Тем не менее этот краткий ответ, вероятно, легче понять, чем десятистраничную программу.
Команды Unix созданы для работы с текстом, именно поэтому позволяют написать такую компактную программу для подсчёта слов. Возможно, shell-скрипт имеет смысл рассматривать как аналог оператора набла для работы с текстом?
Меньше — значит больше
Пример команд Unix выше демонстрирует еще одну характеристику малых языков: менее мощные языки и более высокая производительность. Гонсалес в своей работе «Конец истории программирования» отмечает следующее:
Изучая указанные тенденции, можно увидеть общую закономерность:
Перевод пользовательской задачи в задачу рабочей среды, которая:
... делает программы более схожими с математическими выражениями, и:
... значительно увеличивает сложность рабочей среды.
Регулярные выражения и SQL позволяют вам осуществить только текстовый поиск и операции с базой данных. Их можно противопоставить такому языку как C, где нет рабочей среды и можно выразить всё, что возможно на архитектуре фон Неймана. Высокоуровневые языки, такие как Python и Haskell, занимают промежуточное положение: управление памятью осуществляется автоматически, но у вас всё ещё есть все возможности языка, полного по Тьюрингу, что позволяет выразить любые возможные вычисления.
Малые языки находятся на противоположном конце спектра мощности от C: архитектура компьютера абстрагирована, а также ограничены типы программ, которые вы можете создать — они по своей сути являются неполными по Тьюрингу. Может показаться, что они сильно ограничены, но на самом деле такие языки открывают новые возможности для оптимизации и статического анализа. И, подобно тому, как абстрагирование управления памятью может позволить избежать целого класса ошибок, можно устранить еще больше ошибок, максимально абстрагируясь от алгоритмической работы.
Статический анализ
Языки с меньшей мощностью легче анализировать, и они могут предоставлять более сильные гарантии, чем языки общего назначения. Например, Dhall — это полноценный функциональный язык программирования для создания конфигурационных файлов. Так как вы не хотите рисковать сбоем ваших скриптов развертывания или зацикливанием их, программы на Dhall гарантированно:
Не вызовут сбой и
Завершатся за конечное время.
Первый пункт достигается путем отказа от выбрасывания исключений; любая операция, которая может не удаться (например, получение первого элемента из потенциально пустого списка), возвращает результат Optional, который может быть со значением или без него. Второй пункт — гарантированное завершение — достигается путем запрета рекурсивных определений. В других функциональных языках программирования основным способом описания циклов является рекурсия, но в Dhall вам придется использовать встроенную функцию fold. Отсутствие универсальной конструкции цикла также означает, что Dhall не является полным по Тьюрингу, но поскольку это не язык программирования общего назначения, ему это и не требуется (в отличие, видимо, от CSS).
Если языки небольшие, то анализировать их становится ещё проще. Например, определить, не имеет ли произвольная программа на Python побочных эффектов, сложно, но в SQL это легче — просто проверьте, начинается ли запрос с SELECT
.
Для Nile команда STEPS увидела необходимость в графическом отладчике. Брет Виктор (да, тот самый Брет Виктор, который выступал с докладом Inventing on Principle) разработал инструмент для определения точных строк кода, задействованных при рисовании конкретного пикселя на экране. Вы можете посмотреть демонстрацию Алана Кея на YouTube, а также попробовать сделать это самостоятельно. Такие инструменты возможны благодаря тому, что Nile — это небольшой язык, который легко понять. Представьте, что вы пытаетесь сделать то же самое с графическим кодом на C++!
Жажда скорости
Более продвинутые языки программирования не только увеличивают вероятность ошибок, но и могут негативно повлиять на производительность. Например, если программа не формулируется в виде алгоритма, рабочая среда может выбрать свой собственный алгоритм; медленные выражения могут быть заменены на более быстрые, если мы можем доказать, что они дают тот же результат.
Скажем, SQL-запрос не указывает, как он должен выполняться — механизм базы данных может использовать тот план запроса, который он считает наиболее подходящим, например, индекс, комбинацию индексов или просто просканировать всю таблицу базы данных. Современные движки баз данных также собирают статистику о распределении значений в своих столбцах, чтобы они могли выбрать статистически оптимальный план запроса. Это было бы невозможно, если бы запрос был описан с помощью алгоритма.
Одним из секретных ингредиентов, которые позволили языку Nile стать таким компактным, был Jitblt, JIT-компилятор для рендеринга графики. В ходе обсуждений между командами STEPS и Cairo стало ясно, что большая часть кода Cairo посвящена ручной оптимизации операций с пикселями; работа, которую, в теории, можно было бы передать компилятору. Дэн Амеланг из команды Cairo предложил реализовать такой компилятор, и в результате появился Jitblt. Это означало, что работа по оптимизации графического конвейера могла быть отделена от чисто математических описаний того, что нужно отрисовать, что позволило Nile работать примерно с такой же скоростью, как и оригинальный, оптимизированный вручную код Cairo.
Малые языки, большие возможности
Что случилось с проектом STEPS? Получился ли у них код, эквивалентный «3 кубическим милям прецедентного права», или им удалось создать операционную систему, которая поместится на футболке? Итогом проекта STEPS стала KSWorld — полная операционная система, включающая редактор документов и редактор таблиц, общий объём кода которой составил около 17 000 строк. Хотя такой код сможет поместиться только на очень большой футболке, я бы все равно назвал этот результат успешным.
Создание KSWorld свидетельствует о том, что в малых языках скрыт огромный потенциал. Однако все еще остается множество неотвеченных вопросов, например, «Как эти малые языки должны взаимодействовать друг с другом?» «Следует ли им объединяться в общее промежуточное представление? Или разные рабочие среды должны работать параллельно и взаимодействовать друг с другом через общий протокол (например, конвейер UNIX или TCP/IP)? Или каждый язык настолько мал, что его можно реализовать заново на различных основных языках (как регулярные выражения)? Возможно, язык будущего — это комбинация всего вышеперечисленного?» В любом случае, я уверен, что нам нужно придумать новый подход к созданию программного обеспечения. Возможно, малые языки станут частью этой истории, а может быть, и нет — главное, чтобы мы смогли придумать что-то получше, вместо того чтобы продолжать складывать кирпичи друг на друга.
Дополнительные материалы
Connexion — это API-фреймворк с открытым исходным кодом от Zazzle, который автоматически генерирует конечные точки из спецификации OpenAPI. Обычно OpenAPI используется для описания конечных точек существующего HTTP-сервиса, но Connexion делает всё наоборот — на основе схемы OpenAPI он настраивает сервер API с конечными точками, логикой валидации и живой документацией.
Catala — это декларативный язык, предназначенный для преобразования текста закона в исполняемую спецификацию. Так как он поддерживает немонотонную логику (то есть последующее утверждение может отменить или дополнить предыдущее), он позволяет формулировать программы примерно так же, как пишутся юридические тексты, т. е. как набор утверждений, которые можно изменить или дополнить, добавив новые утверждения.
Racket — это диалект Lisp, специально разработанный для создания новых языков (этот подход иногда называют языково-ориентированным программированием). Я еще не успел основательно поработать с Racket, но он выглядит весьма подходящим инструментом для создания «малых языков». Если это вас заинтересовало, советую прочитать статью «Создание языков в Racket».
Комментарии (63)
gybson_63
15.09.2023 10:46+1Если язык не для алгоритмов, то он не язык программирования. Самый малый язык, который существует - язык машинных кодов =) Чуть больше MASM. Очень лаконичный C. А есть и Erlang.
Будущее языка определяется количеством носителей, документации, практики и количеством постов на SO
Daddy_Cool
15.09.2023 10:46Хм. Пример с уравнениями Максвелла и наблой слишком прост. В математике всё хорошо формализовано, и пожалуйста - есть какой-нибудь Maple.
Я б сказал, если мы можем выделить какие-то объкеты/понятия и они важны большому количеству людей - да, можно сразу ваять новый язык программирования.
event1
15.09.2023 10:46+3Ну то есть академики предлагают разделить проект на два: компилятор "малого языка" и собственно код. Тут есть две проблемы:
всё течёт, всё меняется. Со временем, "малый язык" перестанет удовлетворять требованиям и его придётся улучшать. Тут же вылезут проблемы совместимости, криворукости и всего такого. Просто академики пишут код один раз, публикуют статью и до свидания. В промышленности кодовая база должна жить годами и десятилетиями.
оно уже примерно так и работает. Серьёзный проект строит продукт на внутренних и внешних библиотеках, которые как бы и выступают "малым языком", но при этом находятся в той же кодовой базе и написаны на то же языке, что и сам проект. Что, естественно, куда удобнее, управляемее и долговечнее.
Daddy_Cool
15.09.2023 10:46+6Я как-то давно высказал мысль за которую схватил кучу минусов ))) - зачем нужны новые языки если есть (например) С++ на котором можно написать всё?
Относительно низкоуровневые языки программирования не содержат ограничений, таким образом можно создавать фреймворки, наращивать функционал и т.п... С другой стороны возникает желание сознательно ограничить возможности пользователя, чтобы он не наделал лишнего. На Хабре была статья, что каждая новая парадигма программирования (ООП, ФП) это новые ограничения.
Я сам являюсь (своего рода) автором языка программирования (некий интерпретируемый язык для перемещения координатного устройства и подачи команд на АЦП), и соответственно у нас есть доступ к коду на С++ куда мы постоянно лазим и расширяем возможности - и без этого было бы очень грустно.acsent1
15.09.2023 10:46+4Потому что С++ слишком сложный
Daddy_Cool
15.09.2023 10:46-1Так необязательно же использовать все возможности С++. Си с классами - и достаточно. Ну или сделать некий гиперС++ где можно было бы совсем всё. Ну там - переопределять приоритет операций, вводить любые служебные слова и форматы команд, и т.п... Получился бы такой... анархический С++.
vedenin1980
15.09.2023 10:46+4В Си много устаревших вещей, а предопределение это скорее антипатерн, так как каждый делает свой язык и новому программисту придется учить его с нуля
Вообще упрощённый Си с классами это. Java (ну и C#), так как в основном Java и была построена на идеи — возьмем С++ и отрежем все избыточное и вызывающее головную боль (даже ручное управление памятью из этой оперы.
checkpoint
15.09.2023 10:46А можно пример устаревших вещей в Си ?
Мне на Си написать какую нибудь CGI-шку для простенького сайта с опросом гораздо проще и быстрее чем разбираться с миллиардами фремворков специального назначения. Полностью согласен с предидущим оратором - чрезмерное богатство языков это злейшее зло!
vedenin1980
15.09.2023 10:46+3А можно пример устаревших вещей в Си ?
goto, define макросы, циклы for без foreach и проверки выхода за предела массивов, ручное управление памятью (ну тот спорно, конечно, но оно не нужно для 99% задач).
быстрее чем разбираться с миллиардами фремворков специального назначения… чрезмерное богатство языков это злейшее зло!
Ну и какая связь с фреймворками и самими языками?
Никто вас и не заставляет использовать миллиарды фремворков, на условной java базовый синтаксис (без стандартной библиотеки функций) это несколько десятков конструкций (особенно если не использовать многопоточное программирование) — if, for, switch, while, do while, conts, var, final, return, class, main, public, protected, static, private, enum, interface, try catch finally, throws, import, package, String + 8 примитивных типов и определение массивов. Ну и понимание как определяются класы и функции.
Все остальное опцинальные использование стандартной библиотеки — никто не мешает взять и написать все те же функции самим.
kovserg
15.09.2023 10:46+2А можно пример устаревших вещей в Си?
goto, define макросы, циклы for без foreach и проверки выхода за предела массивов, ручное управление памятью…Вы это сами придумали или кто сказал? Си предназначен для написания небольших утилит и библиотек. Из который потом можно компоновать более сложные конструкции (например с помощью bash или python). Но когда надо строить монолит, оказывается что в нём нет namespace и отделять чужие кирпичи от более чужих с одинаковыми именами вызывает страдания. И в отличии от C++ в C всё делается явно. Например вы не можете в C++ выставить наружу интерфейс со строками или лямбдами, даже в виртуальных таблицах классов могут пропадать методы из за оптимизаций. В Си вы все ваши извороты можете описать явно. Например корутины в Cи вы сможете записать состояние в файл и потом загрузить, а вот C++20 корутинах нет, т.к. там всё от вас скрыто. Зато есть десяток мест кастомизации, и одинаково выглядящий код может делать совершенно не то что вы ожидаете. Не говоря уже об аккуратно разложенных UB которые сразу не видно, но со временем они обязательно всплывают.
blueboar2
15.09.2023 10:46Так можно и дальше спускаться - к ассемблеру и машинному коду. Еще понятнее, еще низкоуровневее. Только писать дольше.
kovserg
15.09.2023 10:46+1каждый новый слой требует больше «кирпичей», чем предыдущий
И каждый использует свои кирпичи и еще переходники к чужим кирпичам и переходники к переходникам переходников тоже.
SadOcean
15.09.2023 10:46+1Ну при всей нашей текущей каше нужно понимать, что подход и так реализуется повсеместно.
Обычно мы не пишем на языке непосредственно, на нем написаны лишь функции доменного языка.
Мы как бы пишем диалект под игры, программы или сайты.
И уже на нем написано конечное приложение.
avshkol
15.09.2023 10:46+14Многие библиотеки питона (pandas, numpy,...) уже можно назвать малыми языками для определённых задач. Но они совместимы с питоном и многие поддерживают элементы друг друга, что лучше, чем отдельные малые языки.
R0bur
15.09.2023 10:46+4В качестве наглядного примера можно привести ядро Linux, которое в 1992 году состояло из примерно 10 000 строк кода. Спустя двадцать лет, его размер достиг около 30 миллионов строк.
Откуда берется столько кода? Я не думаю, что расширение функциональности может объяснить такой рост его объёма; скорее, это связано с нашим подходом к разработке ПО. Обычно новые функции в программе добавляются поверх уже существующих, как при строительстве пирамиды.
Мне кажется, что ядро Linux - не очень удачный пример иллюстрации многослойности ПО. Оно в значительной степени разрослось из-за расширения спектра поддерживаемых платформ и разнообразных периферийных устройств.
vedenin1980
15.09.2023 10:46+6На самом деле проблема надумана — язык это 10% сложности программирования, основная часть сложности это фреймворки, библиотеки, инструменты для разработки и сборки и как сделать что полезное. То есть вся экосистема, возникшая поверх языка. Перейти на другой язык не проблема — перейти на другую экосистему сложно.
Mirn
15.09.2023 10:46+4когда-нибудь запретят создавать новые фреймворки и языки. Если это не запретят ни политики и не управленцы в компаниях то сама физика. Ибо генераторы абстрактных фабрик конфигураторов скриптов сборки нужного тебе проекта порой генерят не саму сборку а скрипт сборки в 40 тыщь раз больше чем сама прошивка.
И написаны настолько криво и убого, что например для просто склейки двух бинарников (загрузчик+прошивку) тянут с собой пайтон третий, а для вычисления CRC32 по обоим бинарникам скачивают тикль, а для записи внутрь бинарника CRC32 LUA и тд.
Горшочек не вари! ведь скоро атомов во вселенной может не хватить чтоб ЭТО заработало /sarcazmDirectoriX
15.09.2023 10:46Ибо генераторы абстрактных фабрик конфигураторов скриптов сборки нужного тебе проекта порой генерят не саму сборку а скрипт сборки в 40 тыщь раз больше чем сама прошивка.
Ох уж этот дивный мир сборки C, где сначала придумали
make
чтобы не писать shell-скрипты для сборки, а потом придумалиautomake
чтоб не писать и тем более не шаблонизироватьMakefile
-ы вручную... В итоге генерируютсяconfigure
-скрипты на 30 тысяч строк, которые затем (через пару минут работы) превращаются вMakefile
на 5 тысяч строк.Mirn
15.09.2023 10:46>В итоге генерируются
configure
-скрипты на 30 тысяч строк, которые затем (через пару минут работы) превращаются вMakefile
на 5 тысяч строк.
это не так плохо, к сожалению не все ITшники видят всю картину целиком: когда они делают отдельные инклудники для отдельных либ, а этих либ много сотен потому что на каждую разновидность периферии по либе, т.е. ADC1 - одна либа, ADC2 уже другая TIMER1 третья а TIMER2 четвёртая потому что первый таймер трёх фазный а второй трёхфазный с dead интервалами и в итоге сотни либ порождают строку конфигурации gcc в десятки тысяч символов в строке ... но вот в скрипте 5 тысяч таких строк
поэтому и получаем под сотню мегабайт скрипт сборки.
(плюс define дофига, плюс каждый *.a или *.lib файл надо отдельно слинковать и тд и тп)PS. И эти люди жаловались на SPL от STM32 где ты просто скопировал или слинковал две папки, инклудников и исходников и установил пару define ов. И все работало как чистые функции без глобальных переменных и состояний.
Sarukazm
15.09.2023 10:46ведь скоро атомов во вселенной может не хватить чтоб ЭТО заработало
И тут на сцену выходят квантовые компьютеры, которые сделают хранение таких объёмов не проблемой!
blueboar2
15.09.2023 10:46+1Не сделают. Квантовые компьютеры - вообще не про хранение больших объемов, и для написания make-ов они точно не помогут.
rrrav
15.09.2023 10:46+1Уравнения Максвелла - очень лаконичные и совершенные, но никак не относятся к языкам программирования.
duke_alba
15.09.2023 10:46+1Интересно видеть как снова просыпается интерес к специализированным языкам. Идеи Н. Вирта снова востребованы :-)
Pavel_nobranch
15.09.2023 10:46+1Программирование это кухня. Где фрэймворки это мясорубки, блендеры и т.д. Обычные языки это ножи, вилки, ложки. А малые языки это открывалки, штопоры, толкушки и т.д. В принципе приготовить блюдо можно только вилкой, ложкой и ножом. Вопрос в эффективности.
Devastor87
15.09.2023 10:46+7Проблема в том, что, как и в случае с пирамидой, каждый новый слой требует больше «кирпичей», чем предыдущий.
Походу, автор видит пирамиды примерно так ????
Rukis
15.09.2023 10:46Видимо имеется ввиду, что сперва мы строим пирамиду, а потом, когда решаем сделать её повыше с сохранением пропорций, то добавляем кирпичей в каждый уровень, начиная с основания.
realbtr
15.09.2023 10:46Интересно, forth это мини язык?
dmiche
15.09.2023 10:46Форт - скорее минималистичный универсальный.
awk - миниязык (хотя, кажется, его преднамеренно заморозили), регекспы, спека sed - миниязыки.
Языки 90х - это простые универсальные инструменты. Их библиотеки линейны, в смысле, просто сокращают длинный код до одной функции. Программисты в это время - универсальны.
Но в 1985 уже появляется Borland TurboVision, 1986 - Erlang/OTP, 1996 - JavaBeans. Это были первые ласточки того, что сегодня называется "фреймворками" и всякий суслик в своей жизни должен написать такой же, но новый. По сути - это и есть определения новых языков, но не доведённые до полной абстракции.
Кстати, в своё время Lisp был идеальным генератором языков и позволял очень "вкусно" кодить снизу вверх - создавать свой язык описания задачи и на нём её формулировать. Но была загвоздка: (чтобы (помнить (порядок (скобочек, аргументов)))), нужно было иметь очень хорошую память. Сегодня есть подсказки в редакторах, есть docstrings, есть ИИ, чтобы транслировать свежеизобретённый набор алгоритмических сущностей на человечий язык и всё это может заиграть вообще новыми красками.
Alexis_Che
15.09.2023 10:46Привет всем! Мне как-то тоже приходили мысли о будущем ЯП. Сказать однозначно какой путь правильный, сложно т. к. я не знаю ВСЕ ЯП, фреймворки и т. д.)). Кажется, что на "каком языке разговаривать" определяется при рождении проекта. С ним (набором технологий разработки ПО) проект и живёт свою жизнь. Если кто знает пример перевода на "другие рельсы"... Думаю это будет не малая статья.
Я хотел бы предложить идею о сближении синтаксиса языков (вероятно один родить будет сложно), но вот пример одних и тех же конструкций на разных ЯП:
fun, func, function
if (a == b) {}, if a==b {}
Разница синтаксиса конструкций switch... case
for...
-
наличие ; в конце строки
И. Т. Д.
Думаю, что такие тенденции, вожможны в будущем.
DirectoriX
15.09.2023 10:46Вы предлагаете обобщить базовый синтаксис, но он и не является проблемой. Выучить ключевые слова и общие правила расстановки скобок и отступов в новом языке можно за день, а то и вовсе автоматически преобразовать имеющийся код к новым требованиям. Примерно тем же самым, только внутри одного языка, уже занимаются программы для автоформатирования кода. Условному astyle достаточно передать ровно 1 аргумент, чтоб привести код к одному из стандартных стилей. Даже если условные JS и Go требуют разного синтаксиса, то их по большей части можно преобразовать друг в друга, что даже сработает для простых случаев типа школьных заданий по информатике (вроде "Пользователь вводит 2 числа, программа должна вывести большее из них, или же написать что они равны").
Настоящая же сложность в том, что разные языки имеют разные библиотеки ( = разные имена системных констант, функций, классов, модулей, ит.д.), а самое главное - зачастую и разные идеи. В браузерном JS нет тредов, в лучшем случае service worker'ы, значит горутины не получится "просто переименовать". А прямого доступа к TCP/UDP нет вообще, только HTTP(S), WebSocket и RTP DataChannel, значит никакую программу, использующую другие сетевые протоколы вы в принципе не можете портировать без значительных изменений. А ни в JS, ни в Go нет поддержки настоящих, системных тредов, которая есть в Rust (и условный tokio позволяет очень легко запускать и таски = гринтреды = горутины). А паттерн-матчинг из того же Rust (
match
) чем заменять,switch
-case
ведь даже близко не подходит - цепочкамиif
-ов?Alexis_Che
15.09.2023 10:46Спасибо за идею! Теперь я буду считать, что не только базовые конструкции ЯП должны выглядеть одинаково, но и имена их базовых библиотек.
А разница в синтаксисе, не является проблемой, так, небольшой раздражающий фактор) когда по запарке путаться начинаешь на чем пишешь в данный момент.))
V_Nikolaevich
15.09.2023 10:46Мне кажется, любой яп можно сделать малым, если не использовать часть его функций.
Новые языки появляются не потому, что они могут делать что то, что нельзя сделать на другом языке программирования, а потому, что у кого-то появилась идея создать что-то новенькое, с другим синтаксисом. Потом это подхватываю вау-энтузиасты, к языку прикручивают библиотеки, которые в данный момент нужны всем и появляется новый яп, на котором удобно писать что-то востребованное. +Этот яп начинают продавать, как будто написанное на нём что то гораздо эффективнее, поэтому покупайте у нас. И пошло, поехало.То же самое можно сделать на любом яп, да хоть на ассемблере, просто нужны соответствующие библиотеки.
То же самое с "малыми яп".
MinaiFenume
15.09.2023 10:46Заметил пару спорных моментов на которых базируется вся статья :)
Объем кода
Суть идеи заключается в том, что когда вы начинаете находить закономерности в своем приложении, вы можете закодировать их при помощи малого языка. Этот язык позволит вам выразить эти закономерности более компактно, чем это возможно с помощью других средств абстракции. Что позволит не только противостоять тенденции к постоянному увеличению размера приложений, но и сократить объём кода в процессе разработки!
Объем кода != когнитивная сложность. При добавлении большего числа инструментов мы усложняем поддержку приложения, поэтому очень не всегда это приведет к позитивным эффектам.
И даже если малый язык позволит реализовать тот же функционал используя более простые абстракции, это все еще может не привести к упрощению поддержки, так как она в большей упирается в количество РАЗНЫХ абстракций, а не количество из переиспользований.
Предел выразительности кода
Я лично убежден, что мы достигли предела выразительности языков общего назначения. Если есть уровень выше, то как он будет выглядеть? Возьмем, к примеру, Python — он настолько высокоуровневый, что практически выглядит как псевдокод.
Не только синтаксис влияет на выразительность языка, а его улучшение не сводится к инкрементальным изменениям. Существуют принципиально различные варианты синтаксиса и написания кода, которые обладают большей выразительностью (LISP vs C-подобные языки, декларативный vs императивный код). И это все может проявляться даже в рамках одного языка.
P.S. Приверы других вещей которые влияют на выразительность помимо синтаксиса: парадигма программирования, фреймворки, набор абстракций используемых в коде, структура файлов проекта, документация (в том числе комментарии), типизация и даже такие вещи как сообщения в коммитах в Git. Все это в совокупности постоянно используется в работе с кодом и у нас впереди еще необъятная возможность к совершенствованию :D
Bbore
15.09.2023 10:46Прочитал статью и вспомнил про недавно прочитанную книгу Кернигана "Время Unix". Он там тоже высоко оценивал роль Yacc и Lex в деле лёгкого создания специализированных языков программирования.
SpiderEkb
15.09.2023 10:46И опять. Пилить дрова удобнее цепной пилой. Нарезать фанеру прямоугольными листами - циркуляркой. Вырезать сложные контуры - лобзиком. Для специальных работ есть специальные пилы (торцовки те же). И почему-то никому в голову не приходит мысль сделать суперуниверсальную вундервафлю которой и деревья валить и нелинейные контуры вырезать было бы одинаково удобно.
IT давно уже разделилась на много разных специализаций. А такое разделение неизбежно влечет за собой создание узкоспециализированных инструментов. И этот процесс так или иначе уже идет - веб-разработка, мобильная разработка, системная разработка... Все это разные стеки.
Попытки создать универсальный язык на все случаи жизни приводят к тому что или этот язык становится очень сложным, а новые стандарты появляются быстрее чем компиляторы их поддерживающие, или все это делается за счет фреймворков и разработчик вынужден тащить огромную кучу зависимостей и при этом не запутаться в версиях.
А теперь представьте что у вас задача с одной стороны связана с работой с БД и какими-то коммерческими вычислениями, а с другой, там есть что-то низкоуровневое типа сокетов, пайпов и т.п.
И для ее решения вам предлагают стек, в котором есть как язык, позволяющий работать с системными делами (сокеты), так и некий специализированный язык, нативно поддерживающий embedded sql, всякие типы данных с фиксированной точкой (фактически, нативная поддержка всех sql типов данных - decimal, numeric, date, time, timestamp и т.п.). Т.е. вам не нужно никаких внешних библиотек, никаких зависимостей, не нужно создавать никаких объектов для работы с тем или иным типом. Просто объявляете структуру записи (причем, ее можно объявить просто ссылкой на формат таблицы в БД), читаете туда запись и работаете с ее полями. И все это на уроне языка и поддерживаемых им типов данных и операций с ними.
И при этом вам дают возможность писать каждую часть задачи на наиболее подходящем для этого языке, а потом объединять все это в один программный объект.
Согласитесь, что нативная поддержка необходимых для реализации бизнес-логики инструментов будет всегда эффективнее, нежели реализация их на уровне внешних зависимостей. Хотя бы потому, что вам не нужно в рантайме создавать объект, реализующий неподдерживаемый языком специфический тип данных - это делается просто объявлением переменной нужного типа и реализуется на уровне компиляции.
Все это звучит несколько непривычно, но когда сам попробуешь на реальных задачах, оказывается очень удобным.
Ada_Belotserkovskaya
15.09.2023 10:46DirectoriX
15.09.2023 10:46Подскажите, почему в уравнениях Максвелла в одном случае операция умножения обозначается точкой, а в других "х"?
Точкой обозначается скалярное произведение (длины векторов умноженные на косинус угла между ними), а крестиком - векторное (результат - вектор, длина = длины векторов умноженные на синус угла между ними, направление - перпендикулярно обоим исходным, пальцы правой руки в раскоряку).
igrishaev
Не нужно путать малые языки с доменными. SQL -- доменный язык, но при этом не малый. Документация к нему составит книгу, а то и не одну в зависимости от движка.
Выдумывать язык под каждую задачу -- это путь в ад. Те, кто программируют на ФП-языках, знают, что в них легко навертеть свой под-язык. Но другим членам команды нужно его учить и дебажить, что сводит на нет начальные преимущества.
igrishaev
Уточню, что сейчас для создания сайта нужно знать:
HTML
CSS
JavaScript
SQL
regex
bash/shell
один из языков бекенда
То есть уже многовато, а в каждом языке свои фремворки. Больше языков => раньше наступит комбинаторый взрыв.
marperia
...или один lisp и разные интерпретаторы!
/s
SUNsung
чтобля?
начнем с того что для создания сайта (просто сайта) сейчас нужно знать только html+css
и то и то можно за день познать и за месяц осознать полностью
регулярки это известное зло, которому не придумали еще никакой замены или даже плохонького онлайн-генератора
в целом регулярки "простые". можно за неделю "осознать" синтаксис и лепить очень сложные выборки по памяти.
но так же регулярки не очевидные, потому спустя год прийдется начинат путь "осознания" заново
SQL вообще не в тему.
если затронули бек, то сейчас все через ORM и для 80% задач хватит базы
если уж реально затрагивать нужное для фронта, так это JS
вот там все плохо, куча подводных.
но и без него можно сделать красивый и анимированый сайт.
а самое главное что сейчас на JS делают все подряд, потому изучив один язык вы легко найдете себе парня и работу
фреймворки != язык
и сейчас фреймворки можно назвать отдельным языком, потому как временами синтаксический сахар становится синтаксисом
vabka
Тут бы определение, что можно считать "просто сайтом"
А деплоить кто будет?
Невозможно эффективно пользоваться ORM и при этом не знать SQL
SUNsung
90% "просто сайта" это визитки или/и лендинги
Сейчас все для людей, взять хостинг и залить на него сайт можно одной мышкой и за 10 мин
Тут соглашусь, но ORM в первую очередь защищает от идиотизма разработчиков, а для селектов, инсертов, апдейтов не нужна какая то глубина понимания. Некоторые живут и процветают с таким уровнем понимания.
MrNutz
А как решит проблему хостинга и деплоя малый язык? Давайте не будем мешать все в кучу.
Если ORM сделана качественно, то SQL можно вообще не знать.
s207883
Зависит от нагрузки. ORM дает удобство, но платить за это приходится скоростью + генератор запросов иногда может упороться и выдать какую-то дичь, так что sql знать нужно.
Ну и полное понимание принципов БД, без тыкания в них палкой при помощи написания всяких селектов и апдейтов, как мне кажется, невозможно.
CrushBy
Вот-вот. И при этом под каждый язык есть свои девелоперы (SQL-разработчик, фронтендер, бэкенд-разработчик). И нас еще часто спрашивали, а зачем мы сделали один язык, на котором можно и в SQL, и в backend и в фронтенд.
Dolios
Не обязательны вообще ни разу.
Это может быть тот же JavaScript.
vasyakolobok77
Ну чисто формально, можно и картинку вместо сайта повесить, тогда вообще знания ЯП не нужно ))) А если серьезно, то если сайт не чистая статика, то так или иначе нужно хранилище данных (не в файлах ж хранить), нужна валидация входных данных (привет регулярочки), ну и как-то надо все это собирать и деплоить (привет шелл скрипты).
Dolios
Хранилище бывает no sql, сборка одной командой осуществляется, скопировать файлы итоговые можно банальным rsync-ом или вообще руками. А для валидации кучу библиотек понаписали. На любителей регулярочек регулярно натыкаюсь. То они точку в имейле запретят, то ещё что-нибудь учудят.
vasyakolobok77
Для валидации может и написали кучу библиотек, но каждый раз заказчик хочет каких-то специальных проверок. В целом-то не суть, изначальный посыл был, что для более менее современного сайта, веб-приложения, корпоративного портала нужно изучать множество технологий, и в среднем по больнице нужен примерно тот стек, что указал автор комментария.
kovserg
Можно WordPress поставить и собирать как из конструктора, докупая недостающий функционал. Да и сам WordPress за вас поставит хостинг.
Ivan22
так WordPress это и есть по сути такой высокоуровневый "малый ЯП" для создания сайтов !!
s207883
Скорее нет, иначе ворд это "высокоуровневый яп для создания документов". Низкоуровневым тогда будет какой-нибудь LaTeX
warus
Любой мало мальский большой проект, представляет собой отдельный язык: набор своих функций и объектов.
Каждый фреймворк-язык приносит с собой головную боль, не устраняя необходимость знания технологий на которых он основан.
Хотя вру ассемблер сейчас знать уже не надо.
Может знания CSS и HTML уйдут в прошлое, что иногда встречаю.
Да и SQL не знают используюя ORM в питоне, а во времена Delphi это было вообще правилом.
Вообщем то самый простой для изучения язык это ASM, и чем выше уровнем язык тем больше функций в языке появляется.
sbw
ASM для изучения может быть и прост, но писать на нём ой как не просто ))
Muzzy0
Это write-only язык ????
DeepFakescovery
а примеры этого утверждения есть?
я думал, что FP форсит других программистов писать функционально, и тогда не только программа становится предсказуемой, но и стиль и логика других программистов в написании программы становятся тоже предсказуемыми.