Генеральная линия: От Fortan до C#

Автор: Виктор Шепелев
Опубликовано в журнале "Компьютерра" №8 от 01 марта 2007 года

Как уже было сказано, подавляющее большинство языков программирования из "настоящего мэйнстрима" ведут свою идеологическую родословную напрямую из машинного языка/ассемблера. Конечно, по этому пути они успели зайти далеко, но каждый следующий шаг был лишь логическим продолжением предыдущего.

В этом "естественном развитии" популярных языков новые концепции вводились путем постепенного "уточнения парадигмы": новые возможности вводятся как почти "синтаксический сахар" (более краткая, удобная и понятная альтернатива существующим конструкциям, ничего принципиально не меняющая), но возникающие нюансы и вопросы и разрешение этих нюансов и вопросов приводит к формулировке новых идей [Для примера: использование именованных переменных вместо регистров и адресов памяти поднимает вопросы о типах данных; структуризация кода с помощью процедур и модулей порождает вопрос "области видимости" переменных, а также разницы между "передачей по ссылке" и "передачей по значению"; и т. п.].

Господствующая парадигма [Любим мы это слово. По большому счету, оно означает "подход", "модель построения программы или ее частей", "способ думать об архитектуре программы" - что-то в этом духе] - программирование императивное: программа - суть набор инструкций "сделай то, потом сделай это", результаты действий сохраняются и изменяются в именованных ячейках - "переменных". Отслеживая историю развития промышленного программирования, можно заметить, что все новые "победившие" языки развивали, а не опровергали эту парадигму.

Первым [Попытки "автоматизировать программирование" были и до Фортрана - "язык" A-0 для компьютера UNIVAC (1952), экспериментальный "транслятор формул", созданный в MIT (1954); но эти реализации показывали чудовищную неэффективность сгенерированного машинного кода, что породило стереотип "никакая автоматизация не сможет заменить человека-программиста, пишущего на ассемблере". Фортран этот стереотип разрушил] реально используемым высокоуровневым языком программирования стал Fortran [Имена ранних языков программирования, как правило, писались большими буквами (FORTRAN, COBOL, ALGOL, LISP…). Причина тут не в склонности к аббревиатурам (довольно вымученным, вроде FORmula TRANslator), а убогость тогдашних средств ввода/вывода, зачастую оснащенных только шрифтами с заглавными буквами. "Как правильно" писать название языка - иногда непонятно и самим авторам, пишут и так и эдак. Мы предпочли вариант, более симпатичный с типографской точки зрения (кроме случаев, когда название языка - явная аббревиатура: PL/I, PHP)] (первое описание - 1954, первая реализация - 1957). В немалой степени перво-Fortran - это "подсахаренный" ассемблер; но это был огромный шаг вперед, хотя бы в том смысле, что вычисление A+BхC можно было записать так, как понятно математику, а не как набор операций по загрузке значений в регистры и вычисления ответов в других регистрах.

НА САМОМ ДЕЛЕ, ЛЮДИ С НАРУШЕНИЯМИ РЕЧИ И СЛУХА НЕЧАСТО «ГОВОРЯТ БУКВАМИ»: ЭТО СЛИШКОМ ТРУДОЕМКО. КРОМЕ ТОГО, В МИРЕ СУЩЕСТВУЮТ СОТНИ,  ЕСЛИ НЕ ТЫСЯЧИ, РАЗНЫХ ЯЗЫКОВ ЖЕСТОВ: КАЖДОЕ КРУПНОЕ СООБЩЕСТВО ГОВОРИТ НА СВОЕМ ДИАЛЕКТЕ И ДАЖЕ АНГЛИЙСКИЙ И АМЕРИКАНСКИЙ ЯЗЫКИ ЖЕСТОВ ЗАМЕТНО ОТЛИЧАЮТСЯ ДРУГ ОТ ДРУГА

Проблемы со структурой программ на Фортране (вкратце: структуры не было) привели к разработке языка Algol (1958). Судьба его весьма показательна: совместная разработка американских и европейских ученых, к которой приложили руку многие "легенды" IT; в процессе работы над Алголом были разработаны концепции структурного программирования (логические структуры для ветвления кода; разбиение программы на процедуры, положившее начало созданию библиотек кода для повторного использования, и т. п.); следующие тридцать лет Алгол будет де-факто стандартом для описания алгоритмов. При этом уклон авторов Алгола в "теорию" (эффективного компилятора нет; стандартных операторов ввода-вывода нет) привел к тому, что использование этого языка в промышленном программировании было мизерным.

Из первоязыков еще стоит упомянуть Cobol (1959), чудовищный как язык, но крайне успешный как платформа для создания бизнес-приложений. Что показательно.

Следующее десятилетие - эпоха экспериментов на ниве создания "самого лучшего языка". В широком использовании продолжают царствовать Fortran/Cobol, к ним добавляются языки класса "все-все-все-в-одном" PL/I и CPL [В этот же период созданы Lisp и Snobol, речь о которых - в следующей статье], тяжелые и для изучения, и для реализации. В районе 70-х происходит первая "большая чистка": парк компьютеров растет лавинообразно, возникает необходимость в языках простых и практичных, которые легко выучить, легко реализовать под различные аппаратные платформы, легко писать и читать код; при этом возрастает количество "программ-ради-программ", не решающих некую бизнес-задачу, а облегчающие работу с самим компьютером.

Си вкупе с Unix; разномастные Бейсики как встраиваемые языки для первых домашних (и мелких недомашних) компьютеров; Pascal в Apple II/Apple III, чуть позже Паскали от фирмы Borland для простого написания программ под DOS, Windows - все это языки весьма простые [Basic, в частности, настолько прост, что даже структурного программирования в нем не было. Зато это давало возможность сделать крайне нетребовательную к ресурсам реализацию языка, что поспособствовало его распространению на "несерьезных" компьютерах. С ростом ресурсов этих компьютеров (и запросов программистов) структурность в Бейсике появилась (в середине 80-х)] и практичные; это, по большому счету, те языки, с которыми программирование стало действительно массовым занятием.

По мере расширения круга задач, решаемых на "простых" языках, количества повторно используемых библиотек и "времени жизни" этих библиотек стали возникать концепции более сложного структурирования кода. Самая популярная из них - объектно-ориентированное программирование; совмещение концепций "набора процедур и данных (модуля)" и "типа данных со сложной внутренней структурой" дало понятие "класса" и "объекта" [Большая часть концепций классического ООП была разработана в середине 60-х в рамках работы над языком Simula (Ole-Johan Dahl, Kristen Nygaard). Судьба его достаточно близка к судьбе Алгола: разработанные концепции были приняты и воплощены во многих успешных проектах, но сам язык использовался весьма ограниченно]. Мэйнстримовая разновидность ООП [О более радикальном наборе концепций с тем же названием - в следующей статье.9 Интересно, что другая разновидность "объектно-ориентированного C", известная под именем Objective C и зачастую воспринимаемая как забавный курьез, была языком вполне постмодернистским, смешавшим концепции классического C и модернистского Smalltalk. Распространение этого (и других "странных") языков исключительно в мире Apple весьма показательно] - естественное эволюционное развитие структурно-императивного подхода. Неудивительно, что и объектно-ориентированные языки, принятые "широкими массами", были естественным развитием все тех же C, Pascal, Basic - Visual Basic, C++ [Интересно, что другая разновидность "объектно-ориентированного C", известная под именем Objective C и зачастую воспринимаемая как забавный курьез, была языком вполне постмодернистским, смешавшим концепции классического C и модернистского Smalltalk. Распространение этого (и других "странных") языков исключительно в мире Apple весьма показательно], Object Pascal (позже Delphi).

О ЯЗЫКЕ ТЕЛА МЫ УЗНАЕМ ОБЫЧНО ИЗ КНИЖКИ АЛАНА ПИЗА С УРОДЛИВЫМИ КАРТИНКАМИ. НО НЕ НУЖНО БЫТЬ ЭКСПЕРТОМ, ЧТОБЫ ПОНЯТЬ, ЧТО ЭТОЙ ДЕВУШКЕ С КРАСИВЫМИ НОГАМИ НЕВЕСЕЛО

Далее мэйнстримовая, структурная парадигма некоторое время дополнялась (например, шаблонами C++, позволяющими писать "обобщенные" классы и "обобщенные" алгоритмы). Но картина мира вновь начала меняться, что привело к очередной "большой чистке" языков и смене расклада, двадцать лет казавшегося незыблемым. По своей важности эти перемены близки к событиям, в результате которых Fortran, Cobol и PL/I сменились Cи, Бейсиком и Паскалем.

Причин тому было много, так что нельзя выделить одну, главную. Важнейшие, видимо, таковы: рост производительности железа, с одной стороны, и востребованности программистов (даже неквалифицированных) - с другой. Поскольку надежность софта становится важнее его быстродействия [В определенных, естественно, пределах. Тем не менее некогда одна из важнейших целей разработчиков C++ - "почти бесплатность (по производительности)" новых концепций - стала анахронизмом]; возникновение и популяризация компьютерных сетей "для всех" (в том числе и Интернета/веба), в результате чего "сетевое программирование" стало всеобщей деятельностью. С точки зрения пресловутых "парадигм" программирования важнейшая тенденция "нового времени" - компонентно-ориентированное программирование: независимые друг от друга компоненты могут быть написаны на разных языках, поставляться в скомпилированной форме, заменяться на лету, взаимодействие между ними должно быть легким, надежным и масштабируемым.

Попытки использования "компонентного" стиля без смены языка (COM/OLE, CORBA) выявили некоторые концептуальные трудности; собственно, попытка создать целостное решение этих трудностей и породила платформы Java и .Net [История Java, впрочем, довольно извилиста; в разное время у Sun было множество разных версий насчет "что это мы делаем и зачем оно надо". Тем не менее на сегодняшний день платформа Java - более или менее прямой конкурент и аналог .Net.]. Их свойства (богатая стандартная библиотека, автоматическое управление временем жизни объектов, наличие виртуальной машины и т. п.) - прямой ответ на те вызовы, которые бросает компонентность. Что же касается языков Java и C# [Заметим, что платформа .Net принципиально многоязычна; Java, изначально бывшая "платформой для одного языка", сегодня движется в том же направлении. Тем не менее мы-то здесь рассматриваем в первую очередь историю языков программирования], то их архитектура и дала мне основания назвать происшедшее "второй большой чисткой": как в свое время C, эти языки стремились вобрать в себя все "хорошие идеи" своего времени, но вдобавок избавиться от наследственной сложности, неоднозначности и других проблем, свойственных C++/Delphi/Visual Basic. Первые версии обоих новых языков таки были проще предшественников, но дальнейшее развитие снова пошло по спирали накопления возможностей и впитывания концепций. Сегодняшний C# - сложный, лаконичный и мультиконцептуальный язык; Java - консервативнее в своем стремлении к простоте и однозначности, но постепенно подбирается к той же планке.

Заполняя пропуски: Концепции

Некоторые языки программирования, близкие "классицизму", но не попавшие в статью, весьма достойны упоминания - хотя бы совсем краткого.

Перечисленные языки - неотъемлемая часть истории развития средств написания программ; тем не менее всеобщая популярность обошла их стороной.

Линейка Pascal. Дело в том, что тот Паскаль, который стал популярным в руках фирмы Borland и который многие из нас учили в школе, от изначальной концептуально-чистой разработки Никлауса Вирта отличается довольно сильно, причем одни считают суть этого отличия "практичностью", другие - концептуальной грязью. Сам Вирт придерживается последнего мнения; будучи невысокого мнения о целостности и чистоте вообще всех широко используемых языков, Вирт и его ученики разработали несколько своих, "чистых и красивых" (Oberon, Modula, Zonnon).

Eiffel. Судьба Эйфелей и их создателя Бертрана Мейерса похожа на судьбу "настоящих Паскалей". Мейерс, как и Вирт, достаточно амбициозен в продвижении своих идей (в основном - об объектно-ориентированном программировании), называя их "единственно правильными"; распространен Eiffel нешироко, влияние его огромно.

Ada. Наконец, создатели самых разных языков программирования среди "вдохновляющих" называют язык Ada, разработанный в 80-х под руководством Пентагона. В каком-то смысле он был аналогом PL/I (не слишком удачная попытка собрать все возможные концепции в одном языке), но некоторые элементы Ada (в частности, ее система типов) оказали большое влияние на мышление авторов других языков.

 

Итоги: завтра была война

Эволюционно нынешние "главные языки" ушли бесконечно далеко от машинных кодов. Накопление парадигм и подходов (а равно и снижение актуальности "простой модели компьютера", которая лежит в основе императивного программирования) практически исчерпало потенциал "классического", структурно-императивного взгляда на программирование, который в сегодняшних компонентных приложениях узнается с трудом. Что придет ему на смену? - этот вопрос мы пытаемся рассмотреть в заключительной статье темы.

Заполняя пропуски: Реализации

Следует упомянуть и еще несколько языковых проектов, вполне классицистических, вполне успешных, но стоящих слегка на отшибе от "главного исторического вектора".

Во-первых, это юниксовский sh и его производные (bash, ksh, csh и далее со всеми остановками). Первые оболочки *nix-систем ведут свой род от Алгола; юниксовский подход к объединению маленьких самостоятельных утилит считается одним из первых примеров компонентно-ориентированного программирования. Среди отдаленных потомков sh - как постмодернистский Perl (о нем мы еще поговорим), так и безусловно классицистический Tcl (а о нем не будем).

Во-вторых, язык веб-программирования PHP - тоже вполне популярен и вполне классицистичен. Его часто называют среди наследников Perl, но от последнего PHP перенял в основном способ именования переменных и область применения; в остальном первые PHP - это почти чистый C (вплоть до имен библиотечных функций). Небывалый успех PHP - это успех не языка программирования (часто критикуемого за концептуальную уродливость), а успех утилиты для легкой разработки веб-приложений. Так и повелось.


<<Хроники чистого разума
Все материалы номера
История, порезанная тонкими ломтиками: Языки программирования. Вдоль и поперек >>