Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Языки программирования. Концепции и принципы
.pdf
Два альтернативных принципа создания ЯП
сами. При этом настоящий параллелизм подразумевается только для так называ
емых периферийных процессов (аппаратных задач, соответствующих внешним
устройствам).
Развитие. Можно создавать операционные абстракции (процедуры и функ
ции) и абстракции данных (именованные типы с возможностью ограничивать на
бор применимых операций – аналог приватных Атипов). Основное средство раз
вития – модуль. Это аналог Апакета.
Защита. Обязательные объявления с соответствующим контролем поведения.
Подразумеваются статический контроль так называемой совместимости типов и
динамический контроль за допустимостью значений переменных. Роль подтипа
по существу играет тип, объявленный как отрезок другого типа. Отрезки одного
исходного типа совместимы между собой и с исходным типом. Формально поня
тие подтипа отсутствует. Производные типы отсутствуют (и формально, и по су
ществу).
Понятие типа и совместимости типов в авторском описании определено нечетко.
Не ясно, какие типы равны. Можно подозревать, что равными считаются типы, на
званные одинаковыми именами. Так как нет производных типов, то операции явно
с типом не связаны (нет проблемы неявного определения операций для производ
ных типов).
Аппарат исключений не предусмотрен.
Мощное средство прогнозирования и контроля фактически предоставляет ап
парат управления видимостью – списки экспортируемых и импортируемых имен.
С их помощью обеспечивается инкапсуляция в рамках модулей (аналогов Апа
кетов).
Исполнитель. Характеризуется набором предопределенных и определяемых
реализацией модулей, в совокупности обеспечивающих рациональное для не
больших компьютеров сочетание общеязыковых (резидентных, постоянно при
сутствующих в компиляторе и (или) целевой машине) и специализированных
средств. Среди последних – аппарат файлового обмена, управления параллель
ными процессами посредством сигналов, управления динамическим распределе
нием памяти.
Архитектура. Характеризуется принципом чемоданчика. Именно поэтому мы
особенно интересуемся Модулой2.
241
12.5. Пример МEпрограммы
Рассмотрим решение уже известной нам задачи об управлении сетями. Цель – со
здание у читателя «зрительного образа» Мпрограмм, а также подробное знаком
ство с теми свойствами ЯП, которые помогут продемонстрировать принцип чемо
данчика. Требования к реализации комплекса услуг по управлению сетями те же,
что и в Аслучае (надежность, целостность, модифицируемость).
Однако в самом начале следует сказать о ключевом понятии Модулы2. Назва
ние этого понятия отражено в названии языка. Конечно, это понятие – модуль.

242
Современное состояние языков программирования
Как и в Аде, спецификация в Модуле2 отделена от реализации. Представлены
они соответственно определяющими (DEFINITION) и реализующими (IMPLE
MENTATION) модулями, аналогами спецификации и тела пакета в Аде.
Продуманная интерпретация фундаментальной концепции модуля – основа
элегантности и конкурентоспособности Модулы2. Именно на этой интерпрета
ции мы и сосредоточим свой анализ.
12.5.1. Управление сетями на Модуле'2
Ниже следует определяющий модуль ПараметрыСети (аналог спецификации со
ответствующего Апакета).
1. DEFINITION MODULE ПараметрыСети;
2. EXPORT QUALIFIED МаксУзлов, МаксСвязей;
3. CONST МаксУзлов = 100;
4. МаксСвязей = 8;
5. END ПараметрыСети;
Как видите, очень похоже на Аду. Отличаются ключевые слова; в идентифика
торах недопустимы разделителиподчеркивания (поэтому применяются большие
буквы для отделения слов); допустимы серии объявлений типов, констант и пере
менных, выделяемых соответствующим ключевым словом; вместо is применяется
знак «=». Короче говоря, Модула2 в перечисленных отношениях ближе к своему
старшему родственнику – Паскалю, чем Ада.
Главное отличие – во второй строке. Она представляет собой так называемый
список экспорта. В нем явно перечисляются те и только те имена, определенные
в модуле, которые считаются доступными (видимыми) в объемлющем контексте.
Точнее говоря, ключевое слово QUALIFIED указывает на косвенный экспорт, ког
да доступны лишь полные имена (с указанием имени экспортирующего модуля):
ПараметрыСети.МаксУзлов и ПараметрыСети.МаксСвязей. При отсутствии этого
ключевого слова имеется в виду прямой экспорт – непосредственно доступны «ко
роткие» имена МаксУзлов и МаксСвязей.
В использующих модулях можно управлять доступом с помощью так называе
мых списков импорта.
12.5.2. Определяющий модуль
1. DEFINITION MODULE УправлениеСетями;
2. FROM ПараметрыСети IMPORT МаксУзлов, МаксСвязей;
(* это список импорта *)
3. EXPORT QUALIFIED Создать, Вставить, Удалить, Связать,
Узел, Связи, Присвоить, УзелЕсть,
ВсеСвязи, Сети;
(* это список экспорта *)
4. TYPE Узел = [1..МаксУзлов];
5. ЧислоСвязей = [0..МаксСвязей];

Два альтернативных принципа создания ЯП
6. ИндексУзла = [1..МаксСвязей];
(* производных типов нет. Все три типа совместимы.*)
7. ПереченьСвязей = ARRAY ИндексУзла OF Узел;
(* регулярный тип (тип массива). Все неформальные массивы – с постоянными
границами. Точнее говоря, границы – константные выражения, вычислимые
в период компиляции. *)
8. Связи = RECORD
9. Число :ЧислоСвязей;
(* инициализации нет *)
10. Узлы : ПереченьСвязей;
11. END;
(* комбинированный тип (тип записи). Допустимы и вариантные.*)
12. Ñåòè;
(* указано только имя типа. Это так называемое непрозрачное объявление типа. Аналог
объявления приватного типа. *)
13. PROCEDURE Создать (VAR Сеть : Сети);
(* В Аде этого не было. Непрозрачные типы могут быть только ссылочными или отрезками предопределенных типов. Содержательные сети у нас – массивы. Поэтому тип "Сети"
будет ссылочным (а никак не отрезком). Реализовать процедуру создания
соответствующего массива можно только в модуле, экспортирующем тип "Сети", то есть
в реализующем модуле УправлениеСетями. Дело в том, что в отличие от Ады приватной
части в определяющем модуле нет. Поэтому нет во внешнем контексте и информации об
устройстве непрозрачных типов (ее нет даже для транслятора). Приходится определять
специальную процедуру создания содержательных сетей. *)
(* Параметр "Сеть" специфицирован ключевым словом "VAR" – это так называемый
параметр-переменная – аналог А-переменной, вызываемой в режиме in out. В результате
исполнения процедуры будет создан указатель на массив-сеть и присвоен формальному
параметру-переменной. *)
14. PROCEDURE Вставить(X : Узел; ВСеть : Сети);
(* Оба параметра – параметры-значения (аналог режима in). Хотя второй параметр
указывает на содержательно изменяющуюся сеть, сам указатель при этом остается
неизменным. *)
15. PROCEDURE Удалить(X : Узел; ИзСети : Сети);
16. PROCEDURE Связать(АУзел, ВУзел : Узел; ВСети : Сети);
17. PROCEDURE Присвоить(Сеть1, Сеть2 : Сети);
(* В Аде этого не было. Во внешнем контексте содержательное присваивание сетей
описать невозможно из-за отсутствия информации об их строении даже у транслятора –
приватной части нет! Поэтому и приходится определять специальную процедуру для
присваивания содержательных сетей. *)
18. PROCEDURE УзелЕсть(X : Узел; ВСети : Сети) : BOOLEAN;
(* Так объявляют в Модуле-2 логическую функцию. *)
19. PROCEDURE ВсеСвязи(X : Узел; ВСети : Сети) : Связи;
20. END УправлениеСетями;
243
Строка 1 – заголовок определяющего модуля. Строка 2 – список импорта. Пе
речисленные в нем имена (экспортированные модулем ПараметрыСети) доступ
ны (прямо, по коротким именам) в модуле УправлениеСетями. Важно, что ника
кие другие внешние имена (кроме стандартных) недоступны. Часть FROM
списка импорта указывает имя модуляэкспортера и тем самым позволяет приме

244
Современное состояние языков программирования
нять короткие имена. Если бы список начинался сразу словом IMPORT, то в нем
должны были бы фигурировать косвенные имена (с точкой) для случая косвенно
го экспорта (и прямые имена для случая прямого экспорта).
Строка 3 – список косвенного экспорта (требующего во внешнем контексте
в общем случае косвенных имен). Косвенный экспорт называют иногда «квали
фицированным», а действие фрагмента FROM – «снятием квалификации». Та
кие обороты выгладят чужеродными в русском тексте.
В строке 12 – непрозрачное объявление типа. По назначению оно соответству
ет объявлению приватного типа в Аде. Во внешнем контексте становится извест
но имя объявленного непрозрачного типа, но применять к его объектам можно
лишь фиксированный набор операций, объявленных в этом же (определяющем)
модуле, так как о природе объектов непрозрачного типа во внешнем контексте
ничего не известно.
Конечно, имя непрозрачного типа и имена соответствующих операций долж
ны быть в списке экспорта. Иначе тип незачем объявлять непрозрачным.
12.5.3. Использующий модуль
MODULE ПостроениеСетей;
(* это главный модуль, ничего не экспортирующий. *)
(* определяющий модуль для главного не пишется. *)
FROM УправлениеСетями IMPORT Создать, Вставить, Связать, Присвоить, Сети;
VAR Сеть1, Сеть2 : Сети;
(* объявление переменных типа Сети. *)
BEGIN
Создать(Сеть1); (* содержательную сеть,*)
(* в отличие от объекта типа Сети – можно создать только*)
(* с помощью импортированной процедуры *)
Создать(Сеть2);
Вставить(33, 13, Сеть1);
...
Присвоить(Сеть1, Сеть2);
(* объекту, указанному Сеть2, присваивается значение объекта, указанного Сеть1. См.
реализующий модуль, экспортирующий тип Сети. *)
END ПостроениеСетей;
В этом модуле отражено уже упоминавшееся важное ограничение, касающееся
непрозрачных типов:
объектами непрозрачных типов могут быть только ссылки (указатели) или
скалярные объекты.
Однако при использовании непрозрачных типов неизвестно, как они устрое
ны. Поэтому с ними можно выполнять лишь операции, явно экспортированные
соответствующим определяющим модулем. Именно поэтому по сравнению с Ада
реализацией добавились операции Создать и Присвоить.
Так что непрозрачные типы Модулы2 по использованию близки к ограничен
ным приватным типам Ады.

Два альтернативных принципа создания ЯП
245
12.5.4. Реализующий модуль
Ниже следует реализующий модуль (аналог тела пакета):
IMPLEMENTATION MODULE УправлениеСетями;
TYPE ЗаписьОбУзле = RECORD
Включен : BOOLEAN;
Связан : Связи;
END;
Сети = POINTER ТО ARRAY Узел OF ЗаписьОбУзле;
(* описание устройства содержательных сетей. *)
(* действует правило последовательного определения. *)
PROCEDURE Создать(VAR Сеть : Сети);
BEGIN
Сеть := NEW Сети;
(* Работает генератор динамического объекта. Создаются объект анонимного регулярного типа (содержательная сеть) и указатель на этот объект. Созданный указатель
присваивается ссылочной переменной – параметру "Сеть". Обратите внимание, в генераторе Модула-2 используется ссылочный тип, а не базовый, как в Аде. Поэтому базовый
вполне может оставаться анонимным. *)
END Создать;
PROCEDURE УзелЕсть(X : Узел; ВСети : Сети) : BOOLEAN;
BEGIN
RETURN ВСети^[X].Включен;
(* "^" означает так называемое разыменование – переход от имени к его значению.
Явное разыменование в Модуле-2 применяется только для объектов ссылочных типов.
"ВСети^" означает массив, на который ссылается указатель "ВСети". Квадратные скобки
выделяют список индексов (алгольная традиция). Точка имеет тот же смысл, что и в
Аде. *)
END УзелЕсть;
PROCEDURE ВсеСвязи(X : Узел; ВСети : Сети) : Связи;
BEGIN
RETURN ВСети^[X].Связан;
END ВсеСвязи;
PROCEDURE Вставить(X : Узел; ВСеть : Сети);
BEGIN
ВСеть^|Х].Включен:= TRUE;
ВСеть^|Х].Связан.Число := 0;
END Вставить;
PROCEDURE Присвоить(Сеть1, Сеть2 : Сети);
BEGIN
Сеть2^ := Сеть1^:
END Присвоить;
PROCEDURE Чистить(Связь, ВУзле : Узел; ВСети : Сети);

246
VAR i : 1 ..МаксСвязей;
(* Переменную цикла нужно объявлять. При этом контроль диапазона менее жесткий, чем
в аналогичной А-программе, так как граница отрезка типа обязана быть константным
выражением. *)
BEGIN
FOR i:= 1 ТО ВСети^[ВУзле].Связан.Число DO
IF ВСети^[ВУзле].Связан.Узлы [i] = Связь THEN
Переписать(ВУзле, i, ВСети);
END (* условия *);
END (*цикла *);
END Чистить;
(* Мы сознательно программируем близко к соответствующей А-программе, хотя можно
было бы действовать рациональнее. *)
PROCEDURE Переписать (ВУзле : Узел;
VAR j : 1.. МаксСвязей;
BEGIN
WITH ВСети^[ВУзле].Связан DO (* присоединяющий оператор *)
FOR j := После ТО Число-1 DO
Узлы [j]:= Узлы [j+1];
END (* цикла *);
Число := Число-1;
END (* присоединяющего оператора *)
END Переписать;
(* Вместо переименования (которого нет) с успехом применен так называемый присоединяющий оператор вида
WITH ИмяЗаписи DO Операторы END
Его смысл в том, что между DO и END селекторы полей записи, указанной посредством
ИмяЗаписи, доступны по коротким именам. В нашем случае это селекторы "Число" и
"Узлы". Присоединяющий оператор имеется и в Паскале. *)
Современное состояние языков программирования
После : ИндексУзла;
ВСети : Сети);
PROCEDURE Удалить(X : Узел; ИзСети : Сети);
VAR i : 1 ..МаксСвязей;
BEGIN
ИзСети^[X].Включен := FALSE;
FOR i:=1 ТО ИзСети^[Х].Связан.Число DO
Чистить(X, ИзСети^[X].Связан.Узлы^[i], ИзСети);
END (* цикла *);
END Удалить;
PROCEDURE Есть_связь(АУзел, ВУзел : Узел, ВСети : Сети): BOOLEAN;
VAR i : 1..МаксСвязей;
BEGIN
WITH ВСети(АУзел).Связан DO
FOR i in 1..запись.число DO
IF Узлы(i) = ВУзел THEN
RETURN TRUE;

Два альтернативных принципа создания ЯП
END;
END;
RETURN FALSE;
END Есть_связь;
PROCEDURE Установить_связь(Откуда, Куда : Узел; ВСети : Сети);
BEGIN
WITH ВСети(Откуда).Связан DO
Число:= Число + 1;
Узлы (Число):= Куда;
END Установить связь;
PROCEDURE Связать(АУзел, ВУзел : Узел; ВСети : Сети);
BEGIN
IF not Есть_связь(АУзел, ВУзел, ВСети) THEN
Установить связь(АУзел, ВУзел, ВСети);
IF АУзел /= ВУзел THEN
Установить связь(ВУзел, АУзел);
END;
END;
END Связать;
END УправлениеСетями;
247
Подчеркнем, что во внешнем контексте доступны только имена из списка
экспорта определяющего модуля. Реализующий модуль может включать лишь
список импорта (когда в нем используются внешние имена, которые не потребо
вались в определяющем модуле). Как и в Аде, все имена, доступные в определяю
щем модуле, доступны и в его реализующем модуле.
Итак, поставленная задача полностью решена. Обеспечена аналогичная Аслу
чаю целостность сетей, модифицируемость комплекса и надежность программи
рования.
Вопрос. За счет чего?
Ответ. Непрозрачный тип «Сети», модульность (в частности, разделение специ
фикации и реализации) и явные объявления (в частности, отрезки типов).
Основной вывод из нашего эксперимента: обычные программы можно писать
на Модуле2 практически с тем же успехом и комфортом, что и на Аде.
Конечно, такие выводы не делают на основании одного эксперимента с неотла
женным и тем более не применявшимся на практике комплексом программ. Однако
для наших целей важно, что при решении поставленной задачи мы ни разу не попа
ли в ситуацию, когда вместо Асредств не нашлись бы подходящие Мвозможности,
не приводящие к необходимости кардинально перерабатывать программу. При
этом задача не подбиралась специально с учетом особенностей Модулы2, а была
просто взята первая задача, на которой мы изучали возможности Ады.
Накоплено достаточно сведений о Модуле2, чтобы содержательно обсудить
принцип чемоданчика в сопоставлении с принципом сундука. Однако так как при
этом не обойтись без сопоставления А и Мрешений, уясним, в каком смысле

248
целесообразно их сопоставлять, насколько это может быть правомерно и почему
поучительно.
Ключевые понятия при ответах на эти вопросы – языковая ниша и авторская
позиция. О втором уже шла речь, а первым займемся в следующем разделе.
Современное состояние языков программирования
12.6. Языковая ниша
Вопрос о том, насколько правомерно сравнивать Модулу2 с Адой как потенци
альных конкурентов, тесно связан с понятием «языковая ниша».
Языковая ниша – это комплекс внешних условий, при которых активная
жизнь двух различных языков невозможна. Языковая ниша (или просто ниша)
характеризуется по меньшей мере классом пользователей ЯП, классом решаемых
задач (проблемной областью), классом инструментальных и целевых компьюте
ров (точнее, программных сред, включающих компьютеры, операционные систе
мы, используемые прикладные пакеты и т. п.). На нишу, соответствующую ЯП,
влияют, кроме собственных свойств ЯП, также особенности технической и соци
альной поддержки (наличие и качество реализаций, экономическая или иная за
интересованность организаций, фирм, ведомств, стран и т. д.).
Сравнивать в качестве потенциальных конкурентов имеет смысл лишь ЯП,
претендующие на одну и ту же или пересекающиеся ниши. Иначе различия между
ЯП всегда можно объяснить различием «условий их активной жизни».
Однако если у конкретного ЯП сформировалась определенная ниша, то бес
перспективно говорить о его вытеснении потенциальным конкурентом. Опыт по
казывает, что справедлив закон консерватизма ниш: ниша сопротивляется заме
не ЯП. Этот же закон можно понимать как закон сохранения (обитателей) ниш.
Поэтому к ЯП (возможно, даже более, чем к программам) применим известный
афоризм В. Л. Темова, который в применении к ЯП можно перефразировать так:
«Языки не внедряются, а выживают».
Так что мало смысла обсуждать, например, замену Фортрана или ПЛ/1 на Аду
или Модулу2 без изменения класса используемых компьютеров, контингента
пользователей, решаемых задач и (или) других характеристик ниши.
Однако сравнивать в качестве потенциальных конкурентов Аду с Модулой2
имеет смысл, хотя в первом приближении это ЯП различного назначения. Ада,
как уже говорилось, ориентирована в первую очередь на программирование
встроенных (встраиваемых) систем с применением кросскомпиляции. А Моду
ла2 – на задачи системного программирования на относительно бедных однопро
цессорных компьютерах.
Реальные языковые ниши для этих ЯП еще не сформировались. Они могут
оказаться конкурентами в ситуациях, когда принцип чемоданчика проявит боль
шую жизнеспособность, чем принцип сундука, даже подкрепленный мощной под
держкой директивных органов.
Так, еще до распространения доступных высококачественных реализаций Ады
Модула2 может «захватить» классы применений, где ресурсы целевого компью
тера позволяют отказаться от кросскомпиляции, если сам компилятор достаточ

Два альтернативных принципа создания ЯП
но компактен. Подробное сопоставление потенциальных ниш Ады и Модулы2
выходит за рамки книги.
Особенно поучительно сравнивать проектные решения с авторской позиции.
В этом случае проектируемые ЯП могут быть предназначены для совершенно раз
ных языковых ниш. Желательно лишь, чтобы сопоставляющий по возможности
четко представлял себе особенности этих ниш и их связь с принимаемыми проек
тными решениями.
При таком подходе принцип чемоданчика как авторский принцип может про
явиться в том, чтобы отказаться от борьбы за определенную нишу, если для этого
не созрели технические или социальные условия. Другими словами, принцип ми
нимальности можно интерпретировать и так, что следует выбирать ниши, где
предлагаемые языковые решения будут выглядеть как совершенно необходимые.
Итак, будем сравнивать А и Мрешения прежде всего с авторской позиции.
Однако учтем, что возможно и пересечение соответствующих ниш.
249
12.7. Принцип чемоданчика
в проектных решениях ЯП МодулаE2
12.7.1. Видимость
Занимаясь управлением видимостью в Аде, мы обнаружили, вопервых, техноло
гические потребности, которые привели к созданию соответствующего Ааппара
та (пакетов, блоков, указателей контекста и сокращений, правил перекрытия и
наследования операций производных типов, переименования, неявных объявле
ний). Вовторых, были продемонстрированы проблемы, вызываемые нежелатель
ным взаимодействием многочисленных компонент этого сложного аппарата.
В частности, было показано, как неявные объявления в сочетании с указателем
сокращений могут приводить к неожиданным последствиям, явно входящим
в противоречие с основной целью ЯП – обеспечить надежное программирование.
Как должен поступить автор ЯП, руководствующийся принципом чемоданчи
ка? Он должен заново проанализировать потребности и поискать компромисс,
в максимальной степени удовлетворяющий критические потребности при мини
мальной возможной сложности предлагаемого языкового аппарата. Ключевая
идея такого компромисса, найденная Виртом для Модулы2, – полный отказ от
любых косвенных (неявных) объявлений.
Компромисс состоит в том, что в первом приближении такая идея должна быть
не слишком удобной для пишущего программу, а иногда и для читающего. Ведь
появляются (потенциально довольно длинные) списки экспортируемых и импор
тируемых имен. Их нужно писать, читать, проверять (и хранить). К тому же по
ним все равно невозможно узнать свойства именуемых сущностей, и приходится
как читателю, так и транслятору анализировать экспортирующие модули. Одна
ко потому это и компромисс, что становятся совершенно тривиальными правила
видимости и контроля имен – ведь все они объявлены явно в каждом модуле.

250
Вместе с тем этот компромисс следует именно принципу чемоданчика. Для
обеспечения раздельной компиляции совершенно необходимо управлять види
мостью имен, смысл которых определен в других модулях. Применяем простей
ший способ – явное перечисление нужных имен с указанием модуляэкспортера.
Получаем списки импорта. Для надежности, облегчения понимания и модифика
ции применяем двойственный конструкт – списки экспорта. Получаем логически
завершенный аппарат связывания модулей.
У принятого решения – несколько важных следствий.
Вопервых, экспортимпорт становится точнее, чем в Аде, где изза правила
последовательного определения видимыми могут оказаться несущественные для
внешнего контекста, по сути промежуточные, имена.
Вовторых, концепция явных объявлений несовместима с концепцией произ
водных типов (с естественными для них неявными определениями операций).
Весьма вероятно, что именно отмеченная несовместимость – одна из причин от
сутствия производных типов в Модуле2. А ведь это целый языковый пласт.
Втретьих, отказ от производных типов не позволяет применять типы в каче
стве характеристики содержательной роли объекта, что меняет саму концепцию
типа. Такого рода последствия можно обнаруживать и дальше.
С одной стороны, они подчеркивают взаимозависимость и взаимообусловлен
ность компонент ЯП как знаковой системы. С другой стороны, указывают цену
компромисса. С третьей стороны, показывают, от каких заманчивых возможно
стей (например, контроль содержательных ролей) приходится отказываться ради
простоты определения, реализации и использования ЯП, помня о неумолимом за
коне распространения сложности.
В связи с управлением видимостью интересно понять, почему в Модуле2 ос
тался присоединяющий оператор (остался от Паскаля). Казалось бы, это полный
аналог указателя контекста и неявные (локальные) объявления полей записи –
очевидное противоречие с концепцией явных объявлений.
Однако серьезного противоречия нет. Скорее, наоборот, можно и здесь усмот
реть следование принципу чемоданчика. Только понимать его нужно глубже,
трактуя «совершенно необходимо» не только в чисто техническом, но и в «соци
альном» смысле. Вопервых, область действия неявных объявлений полей строго
ограничена – между DO и END одного оператора. Вовторых, как было показано,
становятся менее нужными переименования (с такими своими проблемами, как
синонимия – доступ к одному объекту по различным именам; это очень ненадеж
но;
почему?). Втретьих, присоединяющий оператор допускает весьма эффектив
ную реализацию. Запись, с которой предполагается работать, можно разместить
в сверхоперативной памяти, на рабочих регистрах и т. п. С этой точки зрения от
казаться от присоединяющего оператора – решение сомнительное.
Однако, чтобы понять, почему присоединяющий оператор совершенно необ
ходим в Модуле2, нужно привлечь соображения социального характера, явно
учитывающие потенциальную нишу для этого языка. Присоединяющий оператор
совершенно необходим в Модуле2 потому, что он имеется в Паскале (к нему при
выкли те самые пользователи, которые с большой вероятностью начнут поль
Современное состояние языков программирования
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
