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

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

.pdf
Скачиваний:
2
Добавлен:
08.09.2026
Размер:
2 Мб
Скачать
☆
Данные и типы
маска_программы at 1 * слово range 4 .. 7; адрес_команды at 1 * слово range 8..31;
end record;
Здесь применено так называемое УКАЗАНИЕ ПРЕДСТАВЛЕНИЯ ЗАПИ
СИ. Запись типа слово_состояние_программы располагается в двойном слове, то есть по адресам, кратным 8, причем для каждого поля указано расположение от носительно начала записи с точностью до разряда.
Итак, машинно независимые языковые конструкты, примером которых слу
жат средства управления представлением в Аде, позволяют в машинно независи мой форме указывать машинно зависимые характеристики программ. Это один из аспектов ЯП, которые позволяют отнести Аду к «машинно ориентируемым» (но машинно независимым!) ЯП.
Вопрос. Какие еще аспекты Ады можно отметить в этой связи? Подсказка. В Аде немало свойств, «определяемых реализацией», например неко
торые свойства атрибутных функций.
141
4.12. Классификация данных и система типов Ады
Рассматривая данные как одну из основных абстракций программирования, мы выделили семь факторов их классификации. Опираясь на эту классификацию, дадим краткий обзор средств управления данными в Аде с учетом выделенных технологических потребностей.
1. Содержательные роли данных. На первый взгляд, возможность явно от
ражать в программе содержательные роли данных так, чтобы можно было авто матически контролировать связывания, кажется почти фантастической. Теперь мы знаем, что идея очень проста. Вопервых, нужно, чтобы содержательная роль объекта получила имя, отличающее ее от других ролей. Вовторых, проектируя объект данных, нужно связывать с ним имя той роли, в которой он должен выс тупать при выполнении программы. Имя роли естественно указывать при объявлении объекта. Втретьих, проектируя содержательные действия, нужно явно указывать при их объявлении имена ролей объектов, участвующих в этих действиях.
При таком прогнозировании контроль за соответствием поведения объектов
объявленным их ролям становится легко формализуемым. Его обеспечивает концепция типа, ориентированная на имена. В частности, реализованная в Аде концепция уникальности типа.
2. Строение данных. Классификация по структуре данных имеется практиче
ски во всех ЯП. В Аде по этому фактору различаются скалярные, регулярные, комбинированные, ссылочные, задачные и приватные данные. Соответственно, выделяются и категории типов данных. Правила объявления типов данных в Аде таковы, что к одному типу можно относить только данные, формально «близкие»
142
Современное состояние языков программирования
по своему строению. При необходимости подчеркнуть, что данные разного строе ния играют одинаковую содержательную роль, их можно объявить в качестве ва риантов так называемого вариантного комбинированного типа.
3. Изменчивость данных. При объявлении типа данных в Аде всегда сообща
ется максимально допустимая изменчивость данных этого типа. Но когда объяв ляют отдельный объект или целый класс объектов (подтип), изменчивость можно ограничить. Концепция типа в Аде в целом обеспечивает квазистатическое управ ление изменчивостью.
4. Способ определения. Различаются предопределенные типы и объявляемые
пользователем. С этой точки зрения в Аде особенно интересны приватные типы. На уровне использования они инкапсулированы и могут быть сделаны неотличи мыми от предопределенных. Без приватных типов можно вводить новые операци онные абстракции, но не абстракции данных.
5. Представление. Ада позволяет управлять, вопервых, относительным пред
ставлением данных, когда речь идет о представлении приватных типов на уровне их реализации типами иных категорий; вовторых, абсолютным представлением, когда речь идет о представлении любых типов на целевой машине (посредством указаний представления).
6. Внешние свойства. Набором применимых операций в Аде управляют по
средством объявления типа и определяющего пакета.
7. Управление доступом. Доступом в Аде управляют с помощью приватных
типов, приватной части, а также разделения спецификации и реализации пакета. Используют также указатель контекста with, указатель сокращений use, блочную структуру и другие средства.
Вопрос. Какие, например? Подсказка. Ссылочные типы. А еще?
Итак, система типов языка Ада хорошо согласуется с рассмотренной класси фикацией. С другой стороны, эта классификация указывает направления разви тия адовских средств управления данными.
Упражнение. Предложите такие средства. Подсказка. Уже упоминавшиеся модули представления, а также более тонкое
управление доступом, полномочиями, наследованием и т. п.
Наша классификация отражает характеристики данных, обычно охватывае мые концепцией типа. Но данные различаются и по другим факторам. Один из них – отношение данного и модуля программы. Очень четко такое отношение от ражено в языке Том [7] понятием класса данного. Выделены глобальные данные, параметры, локальные и синхропараметры. Аналогичные понятия имеются, конечно, и в других ЯП.
Вопрос. Как вы думаете, разумно ли объединить указанное понятие класса и типа? Подсказка. Не забудьте, в частности, о концепции уникальности типа.
Данные и типы
На этом закончим знакомство с системой типов в Аде. Читателя, заинтересо
ванного в углубленном изучении проблем, связанных с типами, отсылаем к увле кательной книге А. В. Замулина [9].
143
4.13. Предварительный итог по модели А
Итак, выделив три основные абстракции – данные, операции и связывание, мы углубились в основном в изучение первой из них, одновременно получая пред ставление о мощном языке индустриального программирования (фактически мы строим «максимальную» модель такого языка – модель А).
В отличие от традиционных ЯП (Фортрана, Алгола, Бейсика и др.), язык Ада
ориентирован скорее на данные, чем на операции. В нем в первую очередь поддер живается такой стиль программирования, когда проектируется не столько про грамма, сколько комплекс программных услуг, опирающийся на ключевую струк туру данных.
Решая наши модельные задачи в таком стиле, мы одновременно вникали в суть
основных абстракций программирования. Параллельно мы знакомились с раз личными видами операций (для каждой категории типов – свои) и с различными видами связывания (статическое, динамическое, квазистатическое, подразумева емое по умолчанию, выбираемое компилятором, указываемое программистом).
Вне поля нашего зрения осталось еще несколько важных абстракций, которы
ми мы теперь и займемся, одновременно завершая как знакомство с языком Ада, так и построение нашей модели А.
Упражнение. Приведите примеры перечисленных видов связываний.
Вопрос. Как вы думаете, чем отличается модель А от языка Ада?
Глава 5
Раздельная компиляция
5.1. Понятие модуля ...................... 146
5.2. Виды трансляций .................... 146
5.3. Раздельная трансляция .......... 146
5.4. Связывание трансляционных
модулей......................................... 147
5.5. Принцип защиты авторского
права ............................................. 148
146
Современное состояние языков программирования
5.1. Понятие модуля
Одна из важнейших концепций ЯП – концепция модульности. Ей посвящена об ширная литература (полезно почитать, в частности, [12]). В самом широком смысле модуль – это абстракция от контекста, доведенная до воплощения в от дельном объекте, пригодном для хранения, обработки и использования в разнооб разных контекстах с минимальными накладными расходами. Образно говоря, мо дуль проще заимствовать, чем создавать заново (иногда последнее может быть даже запрещено авторским правом).
В связи с тем, что трансляция играет особую роль при использовании ЯП, осо бую важность приобретают различные концепции трансляционных модулей, то есть оформленных по специальным правилам фрагментов текста на ЯП, пригод ных для относительно независимой от контекста трансляции и последующего ис пользования без полной перетрансляции. Относительность указанной независи мости от контекста проявляется в том, что в общем случае для трансляции модуля могут в той или иной степени требоваться фрагменты потенциального контекста. Обычно эти фрагменты находятся в трансляционной библиотеке в форме транс ляционных модулей, содержащих определения имен, используемых, но не опре деленных в рассматриваемом модуле.
5.2. Виды трансляций
Различают так называемую «цельную» трансляцию (модульность отсутствует – транслятору предъявляют всю программу целиком; примером служат стандарт ный Паскаль и первые версии Турбо Паскаля), раздельную трансляцию (предъ являют модуль и трансляционную библиотеку – примером служат Ада и Модула2), «шаговую», или «инкрементную», трансляцию (транслятору предъявляют лишь очередное дополнение или исправление к программе – примером служит инстру ментальная система для создания Адапрограмм на специализированном компь ютере R1000) и, наконец, «независимую» трансляцию (транслятору предъявля ют только один модуль, а связывание оттранслированных модулей выполняется редактором связей или загрузчиком – примером служит Фортран).
У каждого вида трансляции свои преимущества и недостатки, довольно оче видные.
Вопрос. Какие?
5.3. Раздельная трансляция
Раздельная трансляция (компиляция) модулей – одна из критичных техноло гических потребностей индустриального программирования. Без нее практи чески невозможно создавать скольконибудь значительные по объему про граммы (почему?).
Раздельная компиляция
В Аде ТРАНСЛЯЦИОННЫЙ МОДУЛЬ (или просто МОДУЛЬ) – это про
граммный сегмент, пригодный для раздельной трансляции. Иначе говоря, это фрагмент текста, который можно физически отделить от контекста и применять посредством ТРАНСЛЯЦИОННОЙ БИБЛИОТЕКИ.
147
5.4. Связывание трансляционных модулей
Трансляционные модули связываются для того, чтобы взаимодействовать как ча сти единой программы. При этом приходится называть имена партнеров по свя зыванию.
Выделим два основных вида связывания, которые назовем односторонним и
двусторонним соответственно. При одностороннем связывании лишь один из двух связываемых модулей называет имя своего партнера, при двустороннем – оба. В стандартном Паскале и Бейсике трансляционных модулей нет, однако про цедуры вполне можно считать модулями (но не трансляционными, а логиче скими). В Фортране имеются настоящие трансляционные модули (которые так и называются – «модули», а иногда «программные единицы»). Имеются трансля ционные модули и во всех современных диалектах Паскаля (unit в Турбо Паскале начиная с версии 4.0, а также в проекте нового стандарта ИСО). В перечисленных случаях применяется только одностороннее связывание модуля с контекстом (в нужном контексте указывается имя требуемого модуля, но в самом модуле яв ные ссылки на контекст отсутствуют; например в процедуре не перечисляются ее вызовы).
5.4.1. Модули в Аде
Трансляционный модуль в Аде – это такой программный сегмент, все внешние связи которого оформлены как связи с трансляционной библиотекой. Для транс ляционных модулей применяются оба вида связывания. С односторонним связы ванием мы уже фактически познакомились, когда применяли указание контекста (with). Например, трансляционными модулями были: спецификация пакета управление_сетями, процедура построение_сети, родовой сегмент «очередь». Все это примеры так называемых первичных, или открытых (library), модулей. Назва ние «открытых» отражает факт, что в силу односторонней связи этими модулями можно пользоваться открыто, в любом месте программы, для чего достаточно употребить соответствующее указание контекста.
Тело пакета управление_сетью и вообще тела подпрограмм и пакетов без внеш
них связей (кроме связи со «своей» спецификацией) служат примерами так назы ваемых вторичных модулей. Повторение в них тех же имен, что и в первичных модулях, можно трактовать как указание двусторонней связи с соответствующими спецификациями. Ведь на тела можно ссылаться извне только через специфика ции. При этом имя пакета или подпрограммы в заголовке спецификации тракту
148
ется как указание на связь с соответствующим телом, а то же имя в заголовке тела трактуется как указание на связь с соответствующей спецификацией. Так что связь действительно двусторонняя.
Когда же сами спецификации представляют собой внутренние компоненты других модулей, то попрежнему можно оформлять соответствующие таким спе цификациям тела пакетов, процедур и задач как вторичные модули, но для этого нужно явно указать уже двустороннюю связь. Именно: в том модуле, где находит ся спецификация, применяют так называемую заглушку, указывающую на вто ричный модуль, а в заголовке вторичного модуля явно указывают имя того моду ля, где стоит заглушка. Признаком двусторонней связи служит ключевое слово separate.
Например, можно оформить как вторичный модуль тело любой процедуры из пакета управление_сетями. Выберем процедуру «вставить» и функцию «пере чень_связей». Тогда в теле пакета вместо объявления этих подпрограмм нужно написать заголовки вида
function перечень_связей(узел: имя_узла) return BOOLEAN is separate; procedure вставить(узел: in имя_узла) is separate;
Перед нами две ссылки на вторичные модули, две заглушки. Со ответствующие вторичные модули следует оформить так:
separate(управление_сетью); – указано, где находится заглушка для этой функции function перечень_связей(узел: имя_узла) return BOOLEAN is
... – тело как обычно end перечень_связей;
Современное состояние языков программирования
separate(управление_сетью) – указано, где находится заглушка для этой процедуры procedure вставить(узел: in имя_узла) is
... – тело как обычно end вставить;
Теперь вторичные модули «перечень_связей» и «вставить» можно транслиро вать отдельно. В Аде предписан определенный (частичный) порядок раздельной трансляции. В соответствии с ним все вторичные (secondary) модули следует транслировать после модулей с соответствующими заглушками (то есть после «старших» модулей, которые, в свою очередь, могут быть как первичными, так и вторичными).
Итак, ко вторичному модулю можно «добраться» только через его партнера. По этому, в отличие от открытых библиотечных модулей, их естественно называть зак рытыми. Свойство закрытости обеспечено применением явной двусторонней связи.
5.5. Принцип защиты авторского права
Подчеркнем, что закрытые модули появились в Аде не случайно. Они, с одной стороны, естественное развитие разделения абстракции и конкретизации (специ фикации и реализации) до уровня модульности (ведь модуль – это материальное
Раздельная компиляция
149
воплощение абстракции). С другой – они обслуживают важный принцип конст руирования языка Ада, который можно было бы назвать принципом защиты ав торского права (языковыми средствами).
Дело в том, что тексты вторичных модулей можно вовсе не предоставлять
пользователю при продаже программных изделий, созданных на Аде. Ему переда ются только спецификации – открытые модули, а также защищенные от чтения оттранслированные вторичные. Пользователь никак не сможет незаконно до браться до вторичных модулей. При соответствующей защите от несанкциониро ванного доступа он не только не сможет неправильно пользоваться ими, но не сможет и скопировать или употребить для построения других систем (отдельно от закупленных).
Принцип защиты авторского права получил существенное развитие в идеоло
гии так называемого объектноориентированного программирования, восходя щей еще к ЯП Симула67 и в своем современном виде воплощенной в таких но вейших ЯП, как Смолток, Оберон, Си++ и Турбо Паскаль 5.5 (подробности – в разделе «Объектноориентированное программирование»).
Замечание. С учетом идеологии конкретизирующего программирования возника
ет соблазн рассматривать раздельно транслируемый модуль как программу,
управляющую транслятором (интерпретируемую транслятором) в процессе раз
дельной трансляции. Результатом выполнения такой программы может быть мо
дуль загрузки, перечень обнаруженных ошибок и (или) изменения в трансляцион
ной библиотеке. При таком общем взгляде на раздельную трансляцию управление
ею становится столь же разнообразным и сложным, как программирование в це
лом. Такой взгляд может оказаться полезным, когда универсальный модуль рас
сматривается как источник (или генератор) разнообразных версий программы,
учитывающих особенности конкретных применений.
Разнообразными становятся и способы извлечения из внешней среды информации
об указанных особенностях (параметры, анализ среды, диалог с программистом
и т. п.). Так что в общем случае создание универсальных модулей в корне отличает
ся от написания частей конкретных программ. Такие модули становятся метапрог
раммами, описывающими процесс или результат создания частей конкретных про
грамм. Поэтому язык для написания универсальных модулей и управления их
связыванием в общем случае может сильно отличаться от исходного языка про
граммирования (хотя, с другой стороны, есть немало аргументов в пользу их совпа
дения). Рассмотренный общий взгляд по существу выводит за рамки собственно
раздельной трансляции.
Настройка «универсальных» модулей на конкретное применение в Аде есть – ее
обслуживает аппарат родовых сегментов. Но конкретизация родовых сегментов
выполняется не при связывании собственно модулей, а позже, в рамках последую
щей трансляции сегментов.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]