Журнал «Компьютерра» № 8 от 27 февраля 2007 года - Компьютерра Журнал 619 6 стр.


Появление таких языков часто порождает целые новые течения в «программировании-как-искусстве» — соратников, ненавистников, эпигонов и экспериментаторов; но до поры до времени эти течения оставались далеки от «широких масс». Дальше мы пройдемся с широкой сетью по самым заметным из них.

Так много дурацких скобок [Lot of silly parenthesis — «куча глупых скобок» — старинная шуточная расшифровка названия языка Lisp]

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

Глобальность идеи и легкость реализации Лиспа способствовало образованию многочисленного сообщества «фанатов», использовавших любимый язык где ни попадя. В качестве внутреннего макроязыка разновидности Lisp встроены в Emacs и AutoCAD; одно из первых серьезных веб-приложений (viaweb) было написано на нем. За сорок лет споры о деталях и особенностях, практичности и чистоте привели к появлению бесчисленного множества диалектов, главные — Scheme (более изящный, используется в основном в учебе [До недавнего времени знаменитый курс MIT «Структура и интерпретация компьютерных программ» использовал именно Scheme. Месяц назад Scheme вроде бы заменили на Python. Times, they are changing]) и Common Lisp (в каком-то смысле более практичный, но и менее стройный), есть и «более экстремистские», вроде маленького-практичного newLISP или сверх-концептуально-чистого Qi.

Smalltalk

Бывает так: сначала ты «снаружи», вокруг все очень обычное, очень знакомое и скучное. А потом мимо проносится Белый Кролик, при часах и при жилете. Дальше известно что: погоня, несколько минут свободного падения вниз по кроличьей норе — и ты уже «внутри», а из привычного и знакомого остался только ты сам, да и это ненадолго. Такие переживания — когда за поворотом вдруг распахивается целый новый мир — составляют если не смысл жизни, то что-то вроде того.

Три года назад у меня было ощущение, что ничего радикально нового в области технологии разработки ПО мне уже не откроется, а мечта о гибкой, живой и мощной среде программирования… Что ж, на то она и мечта.

Потом случилось так, что я сменил место жительства, а с ним и работу. Там, где я оказался, Smalltalk — не просто инструмент, а жизненная позиция, и даже предмет поклонения. Несколько недель у меня ушло на преодоление собственных предрассудков. Я считал, что сборка мусора несовместима с гарантированными временными характеристиками, что полиморфные вызовы медленны — а тут у меня на глазах ядро авиационного тренажера бодро крутило цикл расчетов сорок раз в секунду.

Труднее всего оказалось воспринять отсутствие границы между инструментами и разрабатываемой программой. «А вдруг, — рассуждал я, — создаваемая программа сделает что-нибудь не так? Ведь тогда рухнет не только она, но и среда разработки!» На практике все оказалось не так страшно. В частности, все изменения пишутся в специальный журнал (change file), откуда в случае аварии виртуальной машины легко восстанавливаются.

Постепенно я стал понимать, что отсутствие границы между инструментом и созидаемым объектом — это чуть ли не главное, что есть в Смолтоке. Вокруг места, где не проходит эта граница, концентрируются вещи, составляющие дух и душу Smalltalk-системы.

Написание кода в отладчике — не эффектный кунштюк, а удобный и практичный способ программировать, когда можно вживую пообщаться с каждым из участвующих в приостановленном вычислении объектов, а не вспоминать мучительно, как называется нужный метод и что именно он возвращает. Возможность затачивать Инспектор под конкретные типы объектов — не просто полезная особенность, а путь к иному способу думать о графическом интерфейсе, когда каждый объект системы способен говорить с человеком на специфическом диалекте единого визуального языка (первоначальное понимание роли графического интерфейса, которое можно проследить в Smalltalk-76 и в Fabrik, было именно таким; теперь мы возвращаемся к сходным взглядам на новом витке спирали в таких средах, как Morphic и Oberon/Bluebottle).

Самое же главное в Смолтоке — это то, что через него программисты необратимо меняются к лучшему. Можно потом писать хоть на ассемблере, хоть на VBA, но это будут уже другой ассемблер и другой VBA. Знание Смолтока необходимо для глубины восприятия. Необходимо, но, конечно, не достаточно, потому что остаются еще Haskell и Erlang, OCaml и Oz, и Scheme, и еще много других путей вниз по кроличьей норе, прямиком в Страну Чудес.

Борис Беркгаут, компания «Транзас» (Санкт-Петербург), отдел ПО авиационных тренажеров

Декларация независимости

Академическое стремление иметь математически стройные средства программирования (к которым были бы применимы математические же методы проверки, доказательства, порождения и вывода) привели к созданию концепции декларативного программирования — идеологически стройного описания программы, которое «выполняется» неким умным компилятором-"думателем" [С термином есть некоторая путаница. Языки описания чего-либо, не являющиеся полноценными «языками программирования» (например, HTML/XML), также называют декларативными]. Разновидности (существенно разные): функциональное программирование — программа описывается как математическая функция, зависящая от других математических функций, затем вычисляется; логическое программирование — задается набор предикатов-утверждений, затем результат выводится из этих предикатов; программирование в ограничениях (constraint programming) — задаются только ограничения на результат, а компилятор вычисляет все результаты, удовлетворяющие этим ограничениям.

Из вышеперечисленных разновидностей лишь функциональное программирование воплотилось в широкую семью языков (языки-потомки «первого функционального» ML, максимально «идеологически чистый» Haskell, странный REFAL, практичный Erlang и другие [Lisp и его потомки постфактум тоже считаются функциональными]) и собрало широкое сообщество «функциональщиков». Сегодня термин «функциональное программирование» определяет как изначальную концепцию (программа-как-вычисление-функции), так и более широкий набор концепций (часть из них не являются обязательным свойством функциональных языков, но возникли именно в этой среде): функции как данные, анонимные функции, продолжения (continuations), сопоставление с образцом (pattern matching) и т. п.

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

Haskell

Включение «привычных» средств в язык делает его ближе и привычнее простому пользователю, но не выразительнее. Выразительнее языка, чем Haskell, я не встречал. До недавних пор у Хаскелла была стратегия «avoid success at all costs», а Тони Хоар печально говорил: «I fear that Haskell is doomed to succeed»; это язык, созданный geek’ами от Computer Science для geek’ов. И поэтому я, при всей любви к Хаскеллу, не могу переключиться на него полностью — без понимания теоретических основ CS я буду знать язык более чем посредственно. Сколько бы популяризаторы ни говорили, что для работы с Хаскеллом не нужны глубокие познания в математике, следует понимать, что потенциал языка будет использован далеко не полностью; дизайн языка и его библиотеки пропитан теорией категорий и универсальной алгеброй.

Глеб Алексеев,

компаниЯ Zoral (Киев)

Одним из критериев оценки языка для меня является лаконичность кода. Haskell — невероятно выразительный и элегантный язык. Дистанция между спецификацией задачи и ее реализацией сильно сокращена. Функции высшего порядка, частичное применение, алгебраические типы данных и сравнение с образцом позволяют писать декларации удивительно близко к оригиналу. Помимо этого вы получаете кучу бонусов, делающих жизнь приятной, — ленивость, строгая типизация без обязательной аннотации типов, полиморфизм. Помню восторг, который я испытал, увидев, что программа после первой же компиляции работала без ошибок. Это было невероятно! Позже я слышал похожие признания от других. TANSTAAFL [ «There Ain’t No Such Thing As A Free Lunch», то есть «Ничего не бывает бесплатно». — В.Ш.]. Для того чтобы начать писать на Haskell, приходится много учиться. Чересчур «другой» язык. Много нового. Совершенно иные подходы к обыденным вещам. Это одна из причин его сравнительно низкой распространенности. К сожалению, вряд ли здесь что-нибудь изменится.

Дмитрий Антонюк, Paragon Software Group

Лучшее детям

Не только академическое сообщество сильно, в пополнении копилки «бесполезных» (смайлик) языков. Smalltalk, «самый объектно-ориентированный язык», создавали люди, среди интересов которых были создание красивых и эффективных пользовательских интерфейсов, доступность компьютеров для детей и джазовая гитара. Алан Кей со товарищи работали в Xerox PARC (как раз в то время и в том месте изобретался весь современный пользовательский интерфейс); язык Smalltalk предназначался для обучения программированию детей; то есть обучению в смысле «сел и начал делать что-то интересное».

Отсюда и основные идеи Smalltalk: «все есть объект»; программа — это не исходный текст, который компилируется, а затем «исполняется», а «живое море объектов, с каждым из которых можно пообщаться». Работа со Smalltalk подразумевает «общение» с этим «живым морем» — средой, в которой можно посмотреть и изменить любой объект; процесс разработки и процесс выполнения суть одно. Этот подход, как можно заметить, существенно отличается от мэйнстримового ООП, с его акцентом на основную сущность — «класс», близкий родственник «модуля» из структурной парадигмы [Алан Кей, «как честный человек», среди предшественников Smalltalk указывает язык Simula, упомянутый в предыдущей статье как прародитель «мэйнстрим-ООП», — но классы и объекты Симулы с классами и объектами Смолтока роднит более терминология, нежели внутренние идеи. Большее влияние на архитектуру языка оказали Lisp, «детский язык» Logo, а в наибольшей степени — программа Sketchpad (см. врезку «Неязыки»)]. В C++ класс — это сущность совершенно иного порядка, нежели объект; в Смоллтоке класс — это тоже объект, и обращаться с ним можно, как с любым другим объектом.

Сегодняшний Smalltalk — исследовательский язык для моделирования сложных систем; и язык «для детей» в виде красочной системы Squeak (как оно и было задумано с самого начала); некоторые интересные идеи современной веб-разработки воплощены в Smalltalk-фреймворке Seaside. Smalltalk породил несколько интересных «детей» — Self (язык с еще более простой объектной системой [Self воплощает концепции «прототипного объектно-ориентированного подхода», в котором есть только объекты, новые объекты порождаются «клонированием» старых; интересно, что изначальные концепции Smalltalk выглядели именно так, а «усложнение» произошло при поиске эффективной реализации. Так что в какой-то степени Self — это «возвращение к корням»]) и Strongtalk (диалект с возможностью статической проверки типов); первый «скорее мертв», второй — недавно был выпущен в open source и потихоньку «оживает».

Неязыки

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

В качестве иллюстрации упомянем программу Sketchpad, разработанную Иваном Сазерлендом в 1963 году для диссертации. Sketchpad не только стала первой программой для компьютерного рисования и реализовала первый графический интерфейс пользователя, но и вводила понятие объекта как основной единицы данных (при этом сама программа была написана на макроассемблере компьютера TX-2). Своим рождением концепция «объектов в стиле Smalltalk» в немалой степени обязана именно Sketchpad’у (Алан Кей некоторое время работал вместе с Сазерлендом).

Еще один пример «программы, которая повлияла на язык», — текстовый редактор ed в Unix, привнесший в «широкие массы» (а также в языки AWK и Perl, далее везде) регулярные выражения как гибкий, универсальный (хоть и запутанный) способ обработки строковых данных.

И обратный, несколько неожиданный пример: наиболее широкое распространение функциональный подход к программированию получил не в каком-либо конкретном языке, а в электронных таблицах вроде Excel. Когда мы определяем одну ячейку как SUM, а другую как AVG и выполняем дальнейшие операции над этими значениями — мы занимаемся именно функциональным программированием (придумал не я, а один из микрософтовцев, разрабатывавших Haskell; см. http://research.microsoft.com/~simonpj/papers/excel/index.htm).

Маленький, но очень-очень гордый

Судьба некоторых немэйнстримовых языков, построенных вокруг идей не слишком общих и глобальных, более печальна, нежели у описанных выше. Отработанная идея с благодарностью подхватывается одним (или несколькими) из более общеупотребимых или просто более новых языков и «растворяется» в преемниках, причем исходный язык (а зачастую и его автор) становится «достоянием истории», монстром, о котором мало кто помнит.

Как пример можно привести линейку Snobol-Icon, языков Ральфа Гриспвольда для обработки строк. В 70-х и начале 80-х эти языки были очень популярными среди разработчиков компиляторов и исследователей ИИ, а затем их идеи вобрал в себя юниксовый AWK (при близких по мощности возможностях обработки строк он наследовал также и Algol-линейку традиционных языков, то есть в целом был более привычен и прост для изучения), а через него эти идеи попали в Perl (наравне с идеями из редактора ed, см. врезку «Неязыки»). Называя «патриархов», Ральфа Гриспвольда часто забывают упомянуть (даже Тьюринговской премии у него не было), он умер несколько месяцев назад не то чтобы «всеми забытым», но явно недооцененным героем.

Судьба языка APL за авторством Кеннета Айверсона (того самого, что написал «Notation as a Tool of Thought») сложилась более счастливо — по крайней мере, «Тьюринга» Айверсону дали. Язык, который расширял привычную математическую нотацию для работы с массивами (все его операторы были одно-двухсимвольными комбинациями, APL требовал особой клавиатуры со спецсимволами), иногда считался «издевательством» и «write-only» языком. Тем не менее «нотация» Айверсона показала свою мощь на задачах, для которых предназначалась (сложные операции с массивами данных); годы спустя появились языки-наследники J (1990, создан Айверсоном как более простая и логичная версия APL) и K (1993, создан учеником Айверсона Артуром Уитни как более простая и логичная версия J), имеющие ограниченную, но устойчивую популярность. На K, к слову, написана коммерческая РСУБД kdb, вроде как являющаяся самой быстрой в мире; по слухам, код ее составляет 26 файлов с однобуквенными именами [Отгадать, какие именно буквы использованы, оставляем как домашнее задание внимательному читателю], в каждом из которых — всего одна страница.

И наконец, для полноты картины упомянем язык Forth, который стоит несколько особняком — по «глобальности задумки» (есть только стек и ничего кроме стека) он находится на уровне Лиспа (по странности внешнего вида — тоже), а по «локальности последствий» — где-то в районе Snobol и APL. Сегодняшнее использование Forth смахивает на «развлечение для понимающих»; языки, на которые повлияли концепции Форта, — несколько экспериментальных гибридов (Kevo, Joy, Factor) да PostScript, язык описания страниц для печатающих устройств.

Lisp

Lisp привлекает своим минималистичным устройством: это самый простой язык с GC. В нем нет ничего наносного, никаких надуманных конструкций, служащих одной цели. Благодаря этому на нем можно реализовать любую парадигму, любое современное свойство других языков программирования. И даже гармонично объединять такие противоречащие друг другу концепции, как функциональный и императивный стили, динамическую и статическую типизации, ленивые вычисления и ООП.

Программируя на Лиспе, просто невозможно зайти в тупик: язык будет поддерживать тот стиль программирования, который вы сами для себя выберете или придумаете. Понятно, что такой подход требует от программиста самых свежих знаний для правильной и лаконичной реализации своих идей, но никто еще не жаловался на то, что ему приходится развиваться.

Те, кто хорошо знают и умеют применять Лисп, никогда не скажут, что какой-то язык может его полностью заменить, что Лисп устарел. Даже если такой программист использует в повседневной практике другой язык, значит, этот язык лучше подходит для решаемых задач или хорошо реализует полюбившуюся программисту парадигму.

Роман Клюйков

Итоги: небо становится ближе

Модернистская традиция в программировании не является ни редкой, ни бедной, ни вымирающей. Тем не менее ни один из вышеописанных языков массовым и общепринятым не стал; солидная их часть нередко используется для практической работы, но в узкоспецифических областях либо людьми, которым на соответствующем языке так удобно думать, что они готовы терпеть некоторые неудобства.

«Оторванность от реальности», свойственная «модернистским идеям», всегда мешала их выходу на «широкую публику» — как напрямую (непонятность), так и косвенно, через вопросы производительности («если язык программирования не естествен для архитектуры компьютера, то чего будет стоить их взаимодействие?»), взаимодействия («как использовать библиотеки на более традиционных языках, коих уже есть много и отказываться от них не хочется?»), наличия программистов («если язык немэйнстримовый, а нам понадобится еще один программист в команду, где мы его возьмем?») [Интересно, что мэйнстрим часто и с удовольствием принимает побочные продукты развития «модернизма» — как технологические решения, вроде сборщика мусора (Lisp и другие) и компиляции в байткод (Smalltalk), так и организационные (популярные понятия рефакторинга, экстремального программирования родились в сообществе Smalltalk)]. Здесь можно провести параллель с судьбой мэйнфреймов и прочих специализированных компьютеров: есть случаи, в которых «вроде бы все понимают», что случай сложный и нужно использовать специальные мощные решения, но «стоимость» этих решений (включая затраты по внедрению, подбору соответствующих специалистов, интеграции со «стандартными частями») такова, что «мы уж сделаем как обычно».

Назад Дальше