Сказки дядюшки Вирта

Никлаус Вирт — один из апостолов программирования. Его авторитет огромен как среди начинающих, так и среди опытных программистов. У нас в стране его знают прежде всего как автора языка Паскаль и книги “Алгоритмы + структуры данных = программы”. Но в развитии своего самого известного языка Вирт не принимает участия примерно с 1975 года; примерно в то же время была написана его самая известная книга. Чем же он занимался эти 30 лет, и что нового он может предложить программистам?

Modula-2 и Lilith
В 1977 году, во время отпуска, Вирт посетил знаменитый исследовательский центр PARC фирмы XEROX. Центр этот разрабатывал языки программирования, ОС и сетевые технологии, при этом умудряясь на своих революционных технологиях практически ничего не зарабатывать. Достаточно сказать, что именно там Стив Джобс подсмотрел идею оконного графического интерфейса, реализованную вскоре в Macintosh, а затем не менее успешно подсмотренную у него Биллом Гейтсом. Вирт тоже был впечатлен “окнами”, однако его больше заинтересовала концепция независимых рабочих станций — аналогов современных ПК. Мы не видим в этом ничего особенного, но надо учесть, что в то время основные вычислительные мощности были сконцентрированы в больших ЭВМ, к которым в свою очередь подключались сотни рабочих терминалов. Перспективность отдельных рабочих станций перед такими монстрами была очевидна, и профессор, вернувшись в родной Швейцарский Федеральный Технологический Институт (ETHZ), занялся реализацией собственного видения этой концепции — машины Lilith.
Как настоящий программист, Вирт начал разработку не с подбора аппаратной части, а с создания нового языка для написания ОС и прикладных программ Lilith. Этот язык получил название Modula-2. Естественно, он был развитием Паскаля, но в отличие от Страуструпа, автора С++, Вирт не стремился усложнить себе задачу обеспечением совместимости со старым языком. Из Modula-2 были смело убраны все BEGIN'ы (вместо “IF ... THEN BEGIN … END ELSE BEGIN … END”, например, пишется “IF … THEN … ELSE … END”), добавили бесконечный цикл LOOP, открытые массивы (то есть массивы, размер которых процедуре изначально не известен), взяли из С оператор RETURN, сразу возвращающий значение процедуры. Любые подпрограммы теперь должны были объявляться как PROCEDURE, даже если они возвращали значение, а в операторе CASE варианты стали отделяться друг от друга символом “|”.

Но все это — лишь косметические изменения; основное же новшество — концепция модулей (что отразилось в имени — MODUlar LAnguage), тоже, кстати, частично подсмотренная в PARC. Модуль в Modula-2 во многом похож на UNIT'ы в Delphi: это отдельная часть кода со своими переменными, типами, константами и процедурами, с разделами объявления интерфейса (DEFINITION MODULE <Имя>) и реализации (IMPLEMENTATION MODULE <Имя>). Каждый модуль может подключать другой модуль (IMPORT <Имя>) и использовать все, что объявлено в разделе интерфейса модуля подключаемого. Любая программа состоит как минимум из одного модуля, с которого начинается ее выполнение. Все библиотеки, естественно, тоже реализуются в виде модулей. Обращение к процедуре, переменной, типу и константе в модуле оформляется как <Имя Моду-ля>.­<Имя элемента>.
Основное отличие модулей в Modula-2 от, например, заголовочных файлов в С/С++ — это раздельная компиляция. Каждый модуль независимо компилируется в отдельный .obj-файл с вызываемым кодом и .sym-файл с описанием интерфейса. При сборке исполняемого файла к основной программе добавляются те импортируемые элементы, которые непосредственно используются в ней. Подобная идея реализована в Delphi — модули тоже компилируются и распространяются отдельно в dcu-файлах, а при сборке линкуются в один exe-файл.
В 1977 году студентами был написан первый 7-проходной компилятор Modula-2 для компьютера PDP-11, выдающий код для Lilith, — за год до появления самой машины! Здесь разработчики применили интересный ход: специально для Modula-2 был разработан оптимальный M-код (аналог байт-кода в Java и .NET), в который и производилась компиляция. Позже был реализован аппаратный интерпретатор этого кода, который и выполнял функции ЦП. Его простота позволила достичь частоты 7 МГц, что было очень неплохо для тех лет, а результирующая производительность системы не уступала только что появившимся 286-м машинам. Продуманность M-кода позволяла получать на выходе файлы в среднем в 3.5 раза меньшего размера, чем у i8086. Такой компактности этот принцип во многом обязан размерам памяти: 128 Кбайт ОЗУ и винчестер на 10 Мбайт. Монохромный дисплей Lilith имел необычную для нас вертикальную ориентацию и разрешение 704×928 пикселей. Естественно, присутствовала и трехкнопочная мышь.

К концу 1980 года силами студентов было собрано 20 таких машин. Тогда же была дописана ОС и создан четырехпроходный компилятор Modula-2, что позволило производить дальнейшее расширение системы уже непосредственно на Lilith. В 1982 году машины соединил Ethernet с пропускной способностью 3 Мбит (в сети даже был выделен файловый сервер с винчестером на 500 Мбайт). Также к ним подключили лазерный принтер. К моменту списания в 1990 году в ЕТН работало 60 таких машин.
Кстати: с середины 80-х у нас в стране разрабатывались станции Кронос, являвшиеся 32-бит развитием идей Lilith и Modula-2. В сентябре 2005 года, при посещении Виртом России, ему была подарена такая станция. Он, в свою очередь, подарил россиянам одну из немногих оставшихся машин Lilith.
В 1984 году за разработку Lilith и языков Modula-2 и Паскаль Вирт получил премию Тьюринга, а год спустя он решил начать новый проект.

Oberon
На сей раз Вирт решил заняться разработкой новой ОС Oberon (названа в честь спутника Урана) для широкого круга рабочих станций, традиционно начав разработку с создания нового языка (который назывался так же, как и сама ОС — Оберон). Вирт опять пошел по пути упрощения языка. Вот что он говорил по этому поводу: “Описание Паскаля занимало около 50 страниц, Модулы-2 — около 40, а Оберона — и вовсе 16. И я рассматриваю эту тенденцию как прогрессивную. Истинная ценность языков программирования зависит от качества и практичности их абстракций”. Сам компилятор был при первой возможности переписан на Обероне, причем уместился в 4000 строк кода (для программ такого рода это практический нереальная цифра!).
Под нож в этот раз попали вариантные записи, цикл FOR (правда, позже Вирт одумался), перечисления и диапазонные типы. Индексирование массивов стало возможно только INTEGER’ом и только с 0. Указатели теперь могли ссылаться только на записи и массивы.
Основное нововведение — довольно необычная реализация ООП. Классов как таковых в Обероне нет, их роль выпол­няют записи, для которых добавлен механизм наследования. В качестве методов выступают внешние процедуры, которым эти записи передаются через параметры. Добавлен оператор <указатель> IS <тип>, проверяющий, указывает ли указатель на нужный тип. Для реализации событий в записи включают поля процедурного типа.
Модули теперь так и остаются в виде .obj-файлов, которые запускаются самой операционной системой. Еще одно нововведение Оберона, тесно связанное с ОС, — сборка мусора: программе не надо освобождать объекты после использования — это безопасно делает сама ОС.
К 2000 году появился Active Oberon, основное отличие которого — нормальная ­реализация ООП и концепция активных объектов, то есть объектов, для которых при создании выделяется отдельный поток, и определенный метод запускается на выполнение параллельно с основной программой. На этом языке написано расширение OberonOS — BlueBottle.

Oberon OS
Эта операционная система является собственной разработкой ETH, причем исходный код “базовой системы” (то есть ядра и основной программы) втиснут всего в 15000 строк. Большая часть системы скомпилирована в байт-код, что позволило создать “ETH PlugIn Oberon” — простой интерпретатор кода для Windows и Linux, позволяющий запускать под этими ОС практический полноценную версию Oberon. Конечно, существует и самостоятельная версия (кстати, ее базовая конфигурация умещается на дискете), но для простого ознакомления хватит и “плагина” (благо он не очень тяжелый — всего 20 Мбайт).
Интерфейс Oberon OS необычен: стандартным является режим, при котором экран вертикально разделен на 2 дока в пропорции 2:1. Левый док используется для пользовательских окон, а правый — для системных и окон настройки. Особенность в том, что окна целиком занимают свой док по ширине, и пользователь может перемещать их только вверх-вниз. Впрочем, имеется и возможность работы с классическим Рабочим столом.
Любой объект (текст, кнопка, список) на экране является редактируемым, то есть пользователь может подправить заголовок любого окна и удалить любую кнопку.
Модульность, доставшаяся Оберону в наследство от Модулы, нашла свое отражение в принципиальной неразличимости программы и библиотеки: для запуска программы пользователь просто вводит имя модуля и процедуры, вызывая ее на выполнение. Вызов осуществляется щелчком средней кнопки мыши по тексту (текст при этом может располагаться где угодно).
Мне особо запомнилось руководство по установке Native Oberon (открывается при загрузке с дискеты), в котором распола­гается строка типа “Partitions.CreatePartition ”, а ниже предлагается ввести вместо размер раздела и щелкнуть средней кнопкой по команде для создания раздела на винчестере.
В режиме рабочего стола становится доступной еще одна функция OberonOS — гаджеты. Гаджет наиболее близок к компоненту в Delphi; это тоже объект определенного класса, имеющий визуальное представление (например, часы). Однако гаджеты имеют большую самостоятельность — они могут существовать как элементы какого-то окна или независимо располагаться в любой точке экрана. У гаджета имеется набор свойств, причем их значения можно изменять “на ходу”.

Где искать?
OberonOS можно скачать с сайта www.oberon.ethz.ch. Причем для установки Native-версии достаточно одного образа дискеты. Там же можно найти список доступных компиляторов, из которых, пожалуй, стоит выделить только Oberon for .NET (www.bluebottle.ethz.ch/oberon.net), и множество книг по языку Оберон.
Если хочется попробовать язык в деле, то определенно стоит скачать BlackBox (www.oberon.ch) — среду разработки под Windows с прекрасной документацией и множеством примеров.

Размышления напоследок…
Из всего обилия наследников Паскаля наиболее адекватным вариантом являются Object Pascal (используемый в Delphi. — НП) и стремительно догоняющий его Free Pascal. Действительно, если Вирт в течение 30 лет упрощал язык, затачивая его под свои экспериментальные ОС, то Borland создавала действительно мощный рабочий инструмент для решения реальных проблем. При всей теоретической эффективности, отсутствие качественных и хорошо документированных компиляторов и IDE не позволяет ни Модуле, ни Оберону догнать Delphi по популярности, а, следовательно, по количеству руководств, статей, сайтов и форумов, в том числе и на русском языке. Практически все нововведения, сделанные Виртом, реализованы Borland в рамках Паскаля, с сохранением совместимости.
Если говорить о других языках, то сторонники Оберона любят сравнивать его с С++ из-за высокой популярности последнего. Конечно, сравнение — не в пользу последнего: в С++ нет проверки размерности массива при обращении к нему, нет сборки мусора, нет раздельной компиляции, зато есть объемные и сложные руководства. Да и адресная арифметика является спорным достоинством, особенно в руках новичка. Однако нормальная реализация ООП и совместимость с С вполне все это компенсируют, а наследники С++ — C# и Java — вовсе лишены этих недостатков.


Рекомендуем почитать: