Pull to refresh

Субботние записки: О мёртвых языках и живой практике

Reading time 7 min
Views 4.2K
Мы все знаем, что в мире создано несколько тысяч языков программирования. Один только список программ Hello, world с сайта Wikibooks включает в себя 230 категорий (полный список на сегодня состоит из 402 элементов). При этом известный рейтинг TIOBE подтверждает очевидное соображение: основная масса этих языков скорее мертва, чем жива. Уже на долю первого десятка языков приходится 76,77% всех учтённых TIOBE проектов. Второй десяток увеличивает эту долю до 85,61%. Стало быть, на оставшиеся 30 языков (TIOBE учитывает лишь первые 50 языков при расчёте процентов) приходится менее 15% упоминаний.

Понятно, что рейтинги заключают в себе некоторую долю лукавства, поскольку даже непопулярный по общим цифрам язык может быть крайне важен для какой-либо узкой сферы. Возьмём любимый здесь многими Erlang или Haskell (39-е и 41-е места рейтинга) или ещё более очевидные Simulink и LabVIEW, вообще не попавшие в Top 50, но незаменимые в своих областях. С другой стороны, очевидно, что языки действительно приходят и уходят, и популярность, скажем, Паскаля обречена на снижение, поскольку на смену идут более прогрессивные языки, метящие в ту же нишу. (Не будем упоминать здесь Delphi, в котором от Паскаля остался разве что базовый синтаксис. У традиционного паскалиста листинг на Delphi может вызывать такой же ступор, какой у меня вызвала первая увиденная мною программа на Visual Basic 6, с этими Private и Public, Option Strict и Dim As, напрочь отсутствовавшими в родном Бейсике ZX Spectrum.)

Однако все языки создавались для чего-то, а не просто так. И перед тем как окончательно отправить тот или иной язык в архив истории, следовало бы полностью осознать его наследие, употребимое в текущей практике программирования. А может статься, что некоторые языки вообще списаны со счетов зазря. Вопрос лишь в том, как грамотно провести ревизию, инвентаризацию всего этого добра из сотен и тысяч языков, как извлечь крупицы смысла из гор отработанной породы? Об этом мне и хотелось бы поговорить. Сразу скажу, у меня нет хороших ответов, но есть хорошие вопросы.

Синдром утёнка и победа остроконечников

Для начала хотелось бы выдвинуть тезис о том, что наиболее популярные языки на сегодняшний день не являются объективно самыми лучшими. Мой бывший научный руководитель как-то раз мрачно заметил: «похоже, чем хуже язык, тем он популярнее». Я не буду идти в своих выводах столь далеко. Достаточно отметить, что популярность любого языка действительно во многом обусловлена внешними факторами.

Наиболее очевидный — «синдром утёнка». Что нам в детстве показали, то мы и любим. А чем дольше мы с какой-либо системой работаем, тем лучше мы её понимаем и, стало быть, тем меньше у нас мотивации переходить на что-либо иное. Я мог бы привести здесь собственную историю, но не вижу в этом особого смысла: скорее всего, большинство программистов знакомы с этим явлением на личном опыте. Правды ради надо заметить, что священные войны «язык vs. язык» малоосмыслены. Исследования наглядно доказывают, что продуктивность разработки практически полностью обеспечивается программистом, а не языком (речь, конечно, о языках примерно одного уровня, способных конкурировать между собой).

Выросший «утёнок» может поспособствовать победе той или иной партии. Так, в своё время в Microsoft сделали ставку на Basic и C++, а в Borland — на Pascal (их решения на C++ явно отставали по времени), последствия чего мы наблюдаем на протяжении уже двух десятилетий. Более свежий пример — язык Objective-C (5-е место в рейтинге TIOBE). Кто бы вспомнил о нём, если бы не Apple? В 2007 году Objective-C находился на малопочётном 46-м месте и, рискну сказать, мог считаться сравнительно мёртвым. Являясь решением далеко не первой свежести (1983 год), этот язык был извлечён на свет божий утятами из Apple и теперь входит в список самых популярных языков в мире.

Спор о верном способе разбиения яйца лишён смысла, и победа партии остроконечников не означает превосходства их идей. Просто так сложились звёзды. Если при изучении нового языка программирования я ставлю цель повысить свои шансы на рынке труда, рейтинг TIOBE полезен. Если же мне хочется копнуть глубже, изучить лучшие образцы архитектуры языка, требуются уже иные критерии выбора. В общем, не отзывайтесь пренебрежительно о полузабытых языках. Тупоконечники способны взять реванш, и может статься, что завтра начнут повсеместно восхвалять совсем другие языки, чем сегодня.

Штурм Форта

Под сильным влиянием моего другого научного руководителя я давно уже присматривался к языку FORTH (38-я позиция в списке TIOBE). Мои эксперименты пока ещё не зашли дальше простейших упражнений, но кое-какие выводы для себя уже сделать могу. Думаю, мой опыт вполне показателен, поэтому хочу остановиться на нём чуть подробнее.

Для начала, что же такое язык Форт? Если совсем коротко, в Форте реализована уникальная система почти отсутствующего синтаксиса. Программа по сути представляет собой последовательность имён, разделённых пробелами:
w1 w2 w3…

Каждое имя (в терминологии Форта — «слово») — это просто вызов соответствующей процедуры, встроенной или определённой пользователем. То есть на языке C эта же программа выглядела бы как
w1(); w2(); w3();…

Слова (процедуры, то бишь) можно определять с помощью следующего нехитрого синтаксиса:
: NewWord w1 w2 w3…; \ при вызове NewWord последовательно вызываются w1, w2, w3,…

В системе существует два стека: один из них (стек возвратов) предназначен для хранения адреса возврата из вызванной процедуры, а с помощью второго (его обычно называют просто «стек») происходит обмен данными. Любая функция может считывать и записывать данные, хранимые на стеках.

Ещё один важный момент: в принципе, программа на Форте компилируется в некий промежуточный код (обычно используют шитый код), а затем исполняется. Но в то же время компилятор является частью системы и всегда доступен. Внутри процедуры можно перейти в режим компиляции и откомпилировать новый фрагмент (например, загруженный с диска). Кроме того, любому слову можно приписать два разных действия: действие в момент компиляции и действие в момент исполнения. Скажем, константы в Форте тоже реализованы через процедуры. В C это бы выглядело примерно так:
double PI() { return 3.14; }

В момент компиляции слово-константа должно выделить для себя память, а в момент вызова — вернуть хранимое значение.

Все эти возможности реализованы буквально пятью-десятью ключевыми словами, встроенными в общий поток разделённых пробелами слов. Всё остальное теоретически может быть реализовано пользователем. Например, нужен вам цикл вида DO...LOOP. Можно запрограммировать его самостоятельно. Слово DO кладёт на стек свой адрес возврата. Далее выполняются слова между DO и LOOP. Слово LOOP проверяет условие цикла, и если цикл надо повторить, LOOP кладёт на стек возврата адрес, сохранённый словом DO. Таким образом, вместо нормального возврата из процедуры система перескакивает опять к DO. Аналогично можно реализовать IF...THEN, SWITCH...CASE, любые структуры данных.

Фактически, любой текст, состоящий из разделённых пробелами слов, можно интерпретировать как корректную программу на языке FORTH. Поэтому с помощью Форта можно реализовать особо мозгодробительную идею domain-specific language: вы превращаете входные данные в выполняемую программу! Иными словами, данные сами себя интерпретируют. Например, пусть слово A печатает текст ".-", а слово B — текст "-...". Тогда выполнение корректной Форт-программы A B A B B приведёт к печати соответствующей последовательности в коде Морзе.

Нередко FORTH поминают как язык магистра Йоды из-за используемой обратной польской записи. На самом деле это всего лишь следствие общего синтаксиса как потока разделённых пробелами процедурных вызовов. Запись вида «5 2 +» интерпретируется как вызов процедуры с именем «5», кладущей на стек число 5, затем «2» (по соглашению любая процедура с числовым именем просто кладёт число на стек). Далее процедура "+" берёт со стека два числа и кладёт обратно результат. Реализация полноценной инфиксной записи была бы противна общему духу языка.

В общем, это несущественная подробность. Гораздо серьёзнее критика Форта как write-only языка. Специалисты возразят, что нечитабельный бред можно написать на любом языке, но реальность действительно состоит в том, что на Форте сделать это гораздо проще. За непревзойдённую гибкость приходится дорого платить. Скажем, принимая аргументы через стек, приходится помнить их порядок следования. Описывать сигнатуры функций можно разве что в комментариях. В математических выражениях это выглядит особенно дико. Скажем, чтобы вычислить значение (a — b) / (a + b) для лежащих на стеке a и b нужно выполнить последовательность
OVER OVER + ROT ROT — /

Надо быть законченным фортером, чтобы счесть этот код читабельным. Впрочем, довольно о Форте. Если вас заинтересовал этот язык, можно обсудить его в другой раз. Нам же пора двигаться дальше.

Разбор полётов

Разумеется, я пишу эту статью вовсе не для того, чтобы познакомить вас с основами языка FORTH. Я лишь хотел продемонстрировать, что даже язык из четвёртого десятка TIOBE, причём язык одинокий в своей идеологии (в отличие от языков Haskell и Erlang, имеющих массу родственников) способен научить совсем иному процессу программирования, указать нестандартный подход к способу проектирования программной системы. Этот способ — нечто большее, чем язык Форт, это стиль мышления, нарабатываемый практикой. Один из участников какого-то форт-форума заметил, что он написал гораздо больше форт-программ на C, чем на Форте.

А теперь вопросы. С ответами и без них.

1. А нужно ли? С первого взгляда кажется, что из «немейнстримных» языков вроде Форта можно выудить массу полезного для профессионального роста. Но где бы взять независимый обзор подходов к программированию (книги вроде Себесты хороши, но не совсем то)? Может, какое-то решение лишь кажется оригинальным и разумным, а на практике это уже давно пройденный этап, доказавший свою несостоятельность?

2. Какие языки? Форт — язык необычный, явно способный дать пищу для размышлений современному программисту. А вот Алгол, например, оказался столь влиятельным, что все его элементы так или иначе перекочевали в другие языки. Разве что отдельные механизмы вроде call by name изучить стоит.

3. Что изучать? Посмотрим правде в глаза: вряд ли я на полном серьёзе завтра начну программировать исключительно на Форте. Скорее, меня бы интересовал некий минимальный базис, который позволил бы проникнуться идеологией языка, но при этом не тратить месяцы на полное погружение. Я бы, может, писал отдельные модули на Форте и подключал бы их к своим C++-проектам.

4. Где брать литературу? Приличные учебники для новичков по Форту были изданы ещё при Брежневе. Сейчас либо публикуют учебные статьи, страдающие от недостатка системности, либо серьёзные книги для серьёзных специалистов. Старые книги не годятся: авторы акцентируют внимание совсем не на тех вещах, на которых стоило бы (в соответствии с современными представлениями). А новых книг недостаёт.

5. Как себя побороть? Читать классические учебники трудно ещё и потому, что тебе снова приходится идти в первый класс. Тяжело тратить все выходные на программирование решения квадратного уравнения или реализацию простейшей картотеки. Хотелось бы специализированных учебных материалов, предназначенных для людей вроде меня. Где не станут подробно расписывать что такое стек или функция, а сразу перейдут к обсуждению принципиальных вещей, ради которых я готов погрузиться в данную тему.

Ну и вообще, есть ли в моих рассуждениях смысл?

Upd: Хочу подчеркнуть, что Форт здесь приведён только в качестве примера, мы не его обсуждаем.
Tags:
Hubs:
+48
Comments 107
Comments Comments 107

Articles