На базарной площади довольно часто можно слышать высказывания об
Обероне. Мне кажется, что на базарной площади пора появиться ветке об
этой системе и языке, что-то вроде "Мысли об Обероне". Что это такое, перспективы
этой системы, что
полезного можно извлечь из него для программирования на Дельфи
(например) и др.
Про историю зарождения концепции модуля я уже писал, сошлюсь на работу "Модульное программирование. Terra Incognita".
http://www.oberon2005.ru/qa191005.html
В свете нашего анализа интересно будет развить поднятые там вопросы.
Модуль появился как естественный механизм абстрагирования. Т.е. его функции не сводятся к примитивной капсуле. Это не просто коробка, в которую положили невесть чего.
Модуль -- прямой и естественный путь к реализации т.н. абстрактных типов данных. Такой тип должен иметь скрытую структуру, а также специфицировать набор операций, которые к нему применимы. Эти операции надо собирать в одном месте (где их реализация будет скрыта и притом будет иметь доступ к закрытой структуре типа).
Модуль в смысле "капсула+интерфейс" (разумеется, это крайне упрощенное восприятие, но его для изложения идей пока вполне достаточно) хорошо справляется с задачей поддержки абстрактных типов данных (АТД).
В наши дни ООП по сути задавило абстрактные типы данных. Поскольку с помощью классов можно реализовывать АТД, а ООП стало панацеей (универсальным лекарством), то внутри понятия класса, как в серной кислоте, растворились понятия АТД и модуля.
Давайте все же будем держать их порознь. Это более полезно для анализа (и, кстати, синтеза). АТД часто является самостоятельной вещью -- ей не нужно наследование. Тем не менее, мы упорно все стараемся делать через классы. Зачем? Да привычка...
Приведу цитату из книги Стива Янга, о которой уже писал.
Конструкцию модуля можно сравнить с неким забором вокруг описанных объектов. Спецификация интерфейса -- это окно в заборе. Видимы только те объекты, которые описаны в окне, и только они доступны из внешней среды. Поэтому конструкция модуля обеспечивает четкую реализацию понятия абстрактных типов данных простым и надежным способом. Модуль гарантирует целостность описанных абстрактным типом данных объектов, не давая внешней среде никакой информации о внутренней структуре типа, и поэтому делает невозможным выбор или модификацию какой бы то ни было компоненты, кроме как с помощью предоставленных операций.
Об особенностях модулей:
1. Модуль группирует логически соотносящиеся объекты в одну единицу, тем самым непосредственно реализуя соответствующее абстрактное понятие, предусмотренное в процессе разработки.
2. Спецификация интерфейса в точности определяет, какие возможности предоставляет модуль внешней среде. Это позволяет отделить приватную часть и поместить ее отдельно от текста главной программы, так что не относящиеся к делу реализационные подробности не затемняют основной идеи разработки.
Обратите внимание вот на что (это осталось за границами книги Янга). С модулем связаны такие понятия как
существование (время жизни),
видимость и
доступ.
Ставится ли между видимостью и доступом в языках Вирта (в отношении модулей) знак равенства? Вопрос для обсуждения.
О языке Modula
В контексте разговора про модульное программирование хотел бы вспомнить еще одну хорошую книгу. Речь о книге Stephen Young "Real Time Languages: Design and Development" (1982). Она вышла в переводе на русский язык в 1985 г. в изд-ве "Мир". С.Янг "Алгоритмические языки реального времени. Конструирование и разработка".
Несмотря на свою "древность" книга интересна до сих пор не только анализом сферы систем реального времени и мультипрограммирования, но и рассмотрением вопросов модульного программирования.
На моей памяти, это, пожалуй, единственный источник на русском языке, где был представлен язык Modula. Да, тот самый язык, который предшествовал языку Modula-2. В силу ряда причин Вирт очень редко вспоминает о той первой своей попытке построить язык модульного программирования. С его легкой руки Modula-2 стали называть просто Modula. Но история есть история. Ее надо изучать, а не вычеркивать.
В эволюции языков Вирта, поддерживающих модульное программирование, есть четкая цепочка Modula --> Modula-2 --> Оберон. Ее внимательное изучение поможет дать ответ на то, почему так, а не иначе решены вопросы в языках Оберон-семейства, которые мы тут рассматриваем.
Поэтому немного расскажу о языке Modula.
Он был разработан Виртом примерно в 1975 г. в ETH. Язык ориентировался сразу на два направления, которые очень увлекли Вирта – модульное программирование и мультипрограммирование (параллельные процессы).
К тому моменту уже вышли статья Дэвида Парнаса по идее разбиения системы на модули и статья того же Вирта (Program Development by Stepwise Refinement). Вирт уже достаточно проработал Паскаль, его группа сделала P-Kit (джентльменский набор для p-кода). Дальше Паскаль двигали американцы. Вирту же было интересно продолжать свои исследования.
При построении нового языка он взял за основу Паскаль, тем более, что язык был чисто экспериментальный, на котором хотелось проверить ряд идей. Но при этом там не обошлось без изменений.
Синтаксис Modula был приближен к каноническому Паскалю (не было требования использовать зарезервированные слова обязательно большими буквами, не было чувствительности к регистру). Если брать уровень операторов (программирование в малом), то уже не было скобок
begin-end (хотя в case для вариантов выбора они еще сохранялись), появилась форма
elsif в операторе
if, был введен цикл
loop, который имел вид
loop
S1 when B1 do X1 exit
S2 when B2 do X2 exit
…
Sn when Bn do Xn exit
S
end
В языке не было оператора
for (так нелюбимого Виртом). Появилось требование завершения имен процедур и модулей их именем рядом со скобкой
end. Не было встроенного ввода-вывода (еще бы, в отличие от Паскаля язык Modula был языком системного программирования). В нем не было
goto, не было типа
real, но был низкоуровневый тип
bits. Не было вариантных записей.
Но главное, были введены новые конструкции, из которых и строилась программа (а не монолитная program в Паскале). Им дали название "модуль". Выделялись разные виды модуля: обычный модуль (
module), монитор (
interface module), драйвер (
device module), а также был введен особый вид процедуры -- процесс (
process).
Рассмотрим некоторые примеры.
module stack;
use element;
define push, pop;
var s: array 1:100 of element; sp: integer;
procedure push (x: element);
begin
sp := sp+1; s[sp] := x
end push;
procedure pop (var x: element);
begin
x := s[sp]; sp := sp-1
end pop;
begin
sp := 0
end stack.
Из этого примера уже видно, что в роли IMPORT выступал
use, а в роли EXPORT –
define. Обратите внимание, что экспорт модуля представлялся в крайней усеченной форме – только перечисление имен, даже без уточнения, что это за сущности, не говоря уже об их видимой части структуры.
Именно поэтому в Modula нельзя было отделить интерфейс от реализации, они как бы слиплись (в Обероне, как вы знаете, они уже "слиплись" совсем в ином виде, на другом витке эволюции языков).
Обратите внимание еще на один важный момент – не было синтаксически разницы между головной программой (оформляемой как модуль) и библиотечным модулем (разве что у головного модуля не было секции экспорта). В языке Modula-2 Вирт их разделил – MODULE – для головного модуля и пара DEFINITION MODULE – IMPLEMENTATION MODULE для библиотечных. В Обероне он вернулся к "совмещению профессий". И это оказалось очень продуктивным.
Что такое
device module -- это особый модуль, который использовал в заголовке приоритет (для уровней прерываний той же PDP-11, на которой это и делалось). Для обработки прерываний использовались переменные (состояние и буфер устройства), отображаемые на абсолютные адреса, а также внутри присутствовала особая process-процедура, у которой явно указывался адрес вектора прерывания (100B -- это 100 в восьмеричной системе счисления).
process clock [100B];
var regstatus[177546B]: bits;
...
end clock;
Точно такое же решение (только без выделения слов device module и без использования process) перешло и в Modula-2.
Процессам надо было общаться. Для этого использовалась знаменитая концепция монитора Хансена-Хоара (с некоторыми поправками в отношении отказа от блокирования входа в процедуры монитора при посылке сигналов). Монитор синтаксически отличался от других модулей зарезервированными словами
interface module.
Вышло три работы Вирта, посвященные этому языку:
1. N.Wirth. Modula: a Language for Modular Programming // Software Practice and Experience, 1977, #7, p.3.
2. N.Wirth. The Use of Modula // Software Practice and Experience, 1977, #7, p.37.
3. N.Wirth. Design and Implementation of Modula // Software Practice and Experience, 1977, #7, p.67.
В 1977 и 1980 гг. вышли еще две работы по этому языку (точнее, по его реализации).
4. J.Holden, I.Wand. Experience with Programming Language Modula (1977).
5. J.Holden, I.Wand. An assessment of Modula // Software Practice and Experience, 1980, #10.
Modula был ярко выраженным языком системного программирования. Это был своего рода ответ Вирта на выход языка Си. Язык Modula заложил большой фундамент для последующих языков Вирта: Modula-2 и Оберон.