Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Языки программирования. Концепции и принципы

.pdf
Скачиваний:
2
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
Именование и видимость (на примере Ады)
211
Например, метки операторов считаются неявно предобъявленными непосред
ственно после всех явных объявлений соответствующей области локализации и тем самым действуют в пределах всей этой области.
Неявные объявления унаследованных подпрограмм. Основные неприятно
сти возникают изза неявных объявлений унаследованных подпрограмм при объявлении производных типов. По замыслу производного типа в момент своего объявления он должен сохранить все те свойства (кроме имени), которые заданы в определяющем пакете родительского типа. Следовательно, вместе с новым ти пом должны считаться объявленными и подпрограммы, унаследованные от роди тельского типа. Но объявленными где? Ведь явных объявлений этих подпрог рамм для нового типа нет, а от точного места объявлений зависит и смысл программы, и результаты контроля.
Упражнение. Приведите примеры такой зависимости.
В Аде эта проблема решается так: все унаследованные подпрограммы считают
ся неявно объявленными сразу вслед за объявлением производного типа. Эти не явные объявления «уравнены в правах» с явными объявлениями.
Далее, если родительский тип был перечисляемым, то производный должен
иметь те же перечисляемые литералы; поэтому их тоже считают объявленными неявно (в качестве функций без параметров).
Вопрос. При чем здесь функции, да еще без параметров?
Подсказка. Эти литералы могут перекрываться, поэтому их удобно считать функ
циями для единообразия правил перекрытия.
Вопрос. А почему можно считать литералы функциями?
Другие особенности механизма объявлений
1. Механизм наследования во взаимодействии с указателем сокращений и
перекрытием оказывается довольно сложным. Подробнее об этом будет
сказано в связи с проблемой сокращений. Основная идея: наследуются
только подпрограммы из определяющего пакета родительского типа, при
чем (важно!) наследование возможно только извне пакета.
2. Формальная область действия неявного объявления метки может оказать
ся существенно шире, чем та часть текста, из которой на эту метку можно
ссылаться. Например, запрещено передавать управление внутрь цикла,
хотя формально внутренняя метка цикла может считаться неявно объяв
ленной вне цикла, после явных объявлений внешней области локализации.
3. Наравне с идентификаторами объявляются строки – знаки операций и
символьные константы. Устройство полных (составных) имен. Общая структура имени такова:
<нечто-без-точки>{.<нечто-без-точки>}
где <нечтобезточки> – это <идентификатор>{нечтовскобках}
В скобках могут быть записаны либо индексы массива, либо аргументы вызова
функции. Заметим, что в Аде возможен элемент массива вида a(i)(j)...
212
Современное состояние языков программирования
Рассмотрим три примера:
procedure Ð is
type Ò is(À,Â,Ñ);
type T1 is array(1..10) of T;
type T2 is record
A2 : T1;
B2 : T1; end record; type T3 is array(1..10) of T2; – Массив записей сложной структуры X : ТЗ;
begin
X(2).A2(3):=C;
end; procedure Q is
package P1 is
package P2 is
type T is ...
end P2; end P1; X : P1.P2.T; – Способ «достать» из пакета нужный тип
... end Q; procedure Ð is
I : INTEGER; ... procedure P1 is
I : INTEGER;
... begin ...
P.I:=P1.I;
P1.I:= P.P1.I+1; (*)
-- эквивалентно I:=I+l;
end P1;
end P;
Последний пример одновременно демонстрирует и мощь средств именования
в Аде. В традиционных ЯП с блочной структурой имя, объявленное во внутрен ней области локализации, закрывает все глобальные омонимы. Другими словами, одноименные объекты в такой области локализации абсолютно недоступны.
В общем случае это не всегда удобно; иногда полезно иметь доступ к закрыто
му объекту (приведите примеры, когда это может понадобиться!).
В Аде достаточно указать полное имя закрытого объекта. Но для этого необхо
димо иметь возможность называть именами области локализации. Поэтому в Аде появились именованные блоки и циклы. (В цикле с параметром объявляется па раметр цикла; имя цикла применяется в операторе выхода из цикла (exit).)
Именование и видимость (на примере Ады)
Упражнение. Приведите примеры применения полных имен для доступа к за крытым локальным переменным блока, к закрытым параметрам цикла, для выхода из вложенного цикла. Воспользуйтесь при необходимости какимлибо учебником по программированию на Аде.
Вопрос. Как вы думаете, разрешен ли в Аде доступ по полным именам извне внутрь области локализации? Постарайтесь ответить, не пользуясь руководством по Аде, опираясь только на свое понимание общих принципов этого ЯП.
213
Итак, денотат полного имени получается последовательным уточнением при
движении по составному имени слева направо.
Применение составных имен. Составное имя может использоваться в следую
щих случаях:
1) именуемая компонента – это компонента объекта комбинированного типа, или вход задачи, или объект, обозначаемый ссылочным значением;
2) полное имя – это объект, объявленный в видимой части пакета, или объект, объявленный в охватывающей области локализации.
Источники сложности. В именуемой компоненте указанные случаи с точки
зрения контекстносвободного синтаксиса не различаются. К тому же в одном и том же полном имени могут комбинироваться несколько случаев.
Пример:
procedure Ð is
package Q is
type T is record
A : INTEGER;
B : BOOLEAN; end record; X:T;
end Q;
begin
... Q.X.A:=1;
end P;
10.7.2. Области локализации и «пространство имен» Ада'программы
Как известно, областью локализации называется фрагмент программы, в котором введены имена, непосредственно доступные в этом фрагменте и непосредственно недоступные вне этого фрагмента. В Аде имеются следующие разновидности об ластей локализации:
• программный модуль (спецификация плюс тело);
• объявление входа вместе с соответствующими операторами приема входа
(вводятся имена формальных параметров);
• объявление комбинированного типа (вводятся имена полей) вместе с соот
ветствующим возможным неполным объявлением или объявлением при
214
Современное состояние языков программирования
ватного типа (вводятся дискриминанты), а также спецификацией пред
ставления;
• переименование (возможно, вводятся новые имена формальных парамет
ров для новых имен подпрограмм);
• блок и цикл. Область локализации физически не обязана быть связным фрагментом.
В частности, возможны области локализации, состоящие из нескольких компили руемых модулей.
Омографы и правила перекрытия. Отличительные особенности областей ло
кализации в Аде – применение полных имен для доступа к непосредственно неви димым объектам и применение перекрытия для борьбы с коллизией имен. Приме ры первого уже были. Займемся подробнее вторым.
В Аде разрешено перекрывать имена операций и процедур (включая предопре
деленные операции, такие как +, –, *, and), перечисляемые литералы (поэтому они и считаются неявно объявленными функциями без параметров) и входы задач (вспомните, вызов входа по форме ничем не отличается от вызова процедуры). Для краткости будем в этом разделе называть имена всех указанных категорий перекрываемыми именами.
Профилем перекрываемого имени (и соответствующего объявления) называ
ется кортеж, составленный в естественном порядке из формальных параметров и результата соответствующей подпрограммы (указываются имена и типы пара метров и результата, если он имеется).
Два объявления одинаковых имен называются омографами, когда их профили
совпадают либо когда одно из имен не относится к классу перекрываемых.
Основное ограничение: омографы в одной области локализации в Аде запре
щены. Вместе с тем во вложенной области локализации имя может быть закрыто только омографом, а не просто объявлением такого же имени.
Пример:
procedure Ð is
function F(X : FLOAT) return INTEGER; I: INTEGER; ... procedure P1 is
function F(X : INTEGER ) return INTEGER;
...
begin
I := F(1.0); – эквивалентно I:=P.F(1.0) ...
I := F(1); – эквивалентно I:=P1.F(1) end F; ...
end P1; ...
end P;
Именование и видимость (на примере Ады)
215
10.7.3. Область непосредственной видимости
Какие же объявления непосредственно видимы из данной точки программы? Нач нем с проблемы видимости для простых имен: определить область (непосред ственной) видимости – множество имен, (непосредственно) видимых (доступных без уточнений с помощью разделителя «.») из некоторой точки программы.
Область видимости в некоторой точке компилируемого модуля конструирует ся по следующей схеме из последовательно объемлющих друг друга частей (бук вы на схеме соответствуют перечисленным ниже частям области видимости):
{-ä-{-ã-{-â-{-á-{-à-}-á-}-â-}-ã-}-ä-},
где
а – объявления, текстуально входящие в рассматриваемый модуль и видимые из рассматриваемой точки по традиционным правилам блочной структуры (с уче том Адаобобщения этого понятия на области локализации – вспомните циклы, объявления комбинированных типов и т. п.);
б – объявления из предопределенного пакета STANDARD, не закрытые объявлениями из части (а);
в – контекст модуля, задаваемый двусторонними связями с программной библиотекой; другими словами, рассматриваются объявления родительских мо дулей, если рассматриваемый модуль – вторичный, и в область видимости добав ляются только те из них, которые не закрываются частями (а) и (б);
г – имена библиотечных модулей, упомянутых в указателе контекста рассматриваемого модуля;
д – объявления из видимой части тех пакетов, имена которых перечислены в видимых указателях сокращений и оказались не закрытыми на предыдущих эта пах. Пример:
package Р is -- первичный библиотечный пакет
I : INTEGER; end Ð; with Ð; use Ð; procedure Q is
-- какова область видимости здесь?
package R is
В : BOOLEAN; end R; -- а здесь? use R; begin
 := TRUE;
I := 1;
end Q;
Вопрос. Зачем на схеме указаны две компоненты каждой из частей (б)...(д)? Каким
объявлениям они могут соответствовать?
Подсказка. Не все объявления предшествуют использованию.
216
Современное состояние языков программирования
10.7.4. Идентификация простого имени
Итак, область видимости построена. Теперь нужно выбрать подходящее объявле ние. Если имя перекрыто, получаем несколько вариантов объявления. Чтобы ото брать нужное, необходимо исследовать контекст использующего вхождения име ни. Тут много дополнительных правил, на которых останавливаться не будем. Если в конечном итоге контекст позволяет отобрать ровно одно объявление, то перекрытие считается разрешенным, а имя – полностью идентифицированным; в противном случае имеет место нарушение языковых законов.
10.7.5. Идентификация составного имени
Идентификация составного имени сводится к последовательной идентификации простых имен и вычислению соответствующих компонент структурных объектов при движении по составному имени слева направо.
Пример:
with PACK; use PACK; procedure P is
package Q is
type T is record
A : T1; В : T2; -- T1 и T2 объявлены в PACK
end record; end Q; use Q; X : T; Y : T1;
procedure PP is
X : FLOAT; ...
begin
P.X.A.:= Y; -- все правильно (почему?)
end PP; end P;
Заметим, что перекрытие может «тянуться» (и «множиться»!) при анализе вдоль имени. Например, перекрытое имя функции может соответствовать двум (или нескольким) потенциальным результатам, каждый из которых может иметь сложную структуру. Это заставляет анализировать каждый из них. Но при этом анализе для продвижения по полученным структурам может снова потребоваться учитывать потенциальные результаты перекрытых функций и т. д. Конечно, так программировать нельзя (ненадежно!), но язык позволяет.
Упражнение. Придумайте соответствующие примеры перекрытий.
10.8. Недостатки именования в Аде
Основные принципы именования в языке Ада рассмотрены. Очевидно, что иден тификация достаточно сложно устроенного имени оказывается нетривиальной. Но не это самое страшное. Оказывается, что именование в Аде не удовлетворяет
Именование и видимость (на примере Ады)
217
одному из основных требований к этому языку – надежности. Основных источни ков ненадежности два. Вопервых, пространство имен компилируемого модуля может формироваться неявно (вспомните об операциях производных типов). Во вторых, смысл указателя сокращений определен столь неестественно, что оказал ся нарушенным принцип целостности абстракций.
Упражнение. Попробуйте найти эту неестественность, не читая пока дальше.
Вспомните, указатель сокращений действует так, что в точке, где он располо
жен, становятся непосредственно видимы имена из видимой части перечислен ных в нем пакетов. Но (с учетом порядка построения области непосредственной видимости) не все такие имена, а только те, которые не закрыты именами, непос редственно видимыми в этой точке без указателя сокращений. Здесь самое глав ное – в том, что «не все». Обоснование у авторов, конечно, имеется, однако оказы вается нарушенным важнейший принцип – принцип целостности.
Действительно, если пакет – логически связанная совокупность ресурсов, или,
иными словами, модель мира, то указатель сокращений по основной идее, «вскры вая» пакет, позволяет удобно работать с этой моделью. Однако в томто и дело, что пакет может быть вскрыт не полностью, и тогда целостность модели оказыва ется нарушенной.
Пример:
package Ð is -- модель мира:
type T1 is range 1..10; -- òèïû, ... type Ò10 is ... procedure P1 ... -- процедуры, ... procedure P10 ... I1 : T1; -- переменные I10 : T10;
end P; with P; use P; -- работа в модели мира Р procedure К is
-- нет объявлений имен Т1-Т10, Р1-Р10, I1-I10 begin
I1:= 1; -- I1 – компонента модели ... declare -- блок, область локализации
type T1 is range -10.. 10;
I1 : INTEGER;
... -- работа не в модели
use Ð;
-- казалось бы, снова нужна модель Р
begin -- но I1 будет не то !!
I1:= 1; -- I1 не из модели, целостность модели нарушена!! I2:= 1; -- I2 снова в модели !!
...
218
Упражнение. Постарайтесь найти доводы в пользу адовской семантики указателя сокращений. Ведь зачемто она определена именно так!
Подсказка. Авторы отдавали приоритет явным объявлениям перед неявными (ра зумно, если не противоречит более важным принципам).
Современное состояние языков программирования
Еще более запутанные ситуации возможны при сочетании указателя сокраще ний с неявными объявлениями операций для производных типов. Ведь такие объявления равноправны с явными объявлениями!
Упражнение. Придумайте соответствующие ситуации (например, когда имя из модели мира становится недоступным изза наследуемой операции, объявленной в весьма «отдаленном» пакете).
Итак, доказана неформальная теорема о свойствах аппарата именования в Аде: именование в Аде сложное и в определенных сочетаниях опасное, нарушающее важнейшие общеязыковые принципы. Вместе с тем этот аппарат по сложности и выразительной мощи в значительной степени согласован с аналогичными харак теристиками языка в целом.
Глава 11
Обмен с внешней средой
11.1. Специфика обмена ............... 220
11.2. Назначение и структура
аппарата обмена ........................... 223
11.3. Файловая модель обмена
в Аде .............................................. 224
11.4. Программирование
специальных устройств ................. 233
220
Современное состояние языков программирования
11.1. Специфика обмена
До сих пор мы занимались внутренним миром исполнителя, игнорировали одну из важнейших технологических потребностей – потребность управлять обменом данными между исполнителем и внешней средой (управлять, как часто говорят, вводомвыводом данных). Настало время поговорить о связи исполнителя с внеш ним миром.
Конечно, можно считать, что такая связь обеспечивается соответствующими базисными операциями исполнителя; они имеются в каждом исполнителе (поче
му?
). Управление обменом состоит в указании подходящей последовательности
таких базисных операций. Казалось бы, никаких особых проблем.
На самом деле управление обменом обладает целым рядом особенностей, со здающих специфические проблемы на всех уровнях проектирования – от созда ния аппаратуры до создания конкретных прикладных программ.
Источник всех таких проблем – в потенциально неограниченной сложности, изменчивости и непредсказуемости внешней среды, исключительном разнообра зии требований к обмену с ее стороны. Коротко говоря, внутренний мир испол нителя обычно несравненно беднее и определеннее, чем его внешний мир.
Конечно, проектировать связь исполнителя с внешним миром в каждом конк ретном случае удается только за счет построения моделей внешнего мира, с нуж ной степенью подробности отражающих его особенности. Базовый ЯП должен содержать средства для построения таких моделей. Другими словами, в нем долж ны быть подходящие средства абстракции и конкретизации. Вместе с тем возмож ны и встроенные в язык готовые модели, которые авторы ЯП посчитали особо значимыми.
И то, и другое есть в Аде. Перечислим специфические особенности внешнего мира с точки зрения обмена, дадим общую характеристику соответствующего ап парата абстракцииконкретизации, а затем продемонстрируем его реализацию в Аде.
1. Внешние объекты и их относительная независимость от исполнителя.
Первая особенность – в том, что объекты внешней среды и связи между ними, в отличие от внутренних объектов исполнителя, не находятся под его контролем пол ностью. Такие объекты могут возникать вне программы, взаимодействовать и изме няться, а также исчезать совершенно независимо от действий исполнителя. С точки зрения ЯП, это означает принципиальную невозможность полностью зафиксировать в языке смысл взаимодействия исполнителя с любым мыслимым внешним объектом. Для области встроенных систем, характеризуемой исключительным разнообразием внешних объектов, это означает необходимость иметь в базовом ЯП средства описа ния взаимодействия с объектами заранее неизвестной природы.
Например, в Аде это уже знакомые нам средства определения новых типов вместе с детальным управлением конкретным представлением объектов (вплоть до программирования в терминах другого ЯП).
Характерное проявление относительной независимости внешних объектов – невозможность определить в ЯП единый метод их именования. Поэтому в базо
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]