Если составной тип имеет подкомпонент личного типа и описан вне па­кета, содержащего описание этого личного типа, то неявно описанные при описании составного типа операции включают все операции, которые зави­сят только от характеристик, следующих из одного описания личного типа. (Например, операция < не включается в набор операций для одномерного индексируемого типа).

Если составной тип сам описан внутри пакета, содержащего описание личного типа (включая внутренний пакет или настраиваемый пакет), то неявно описываются дополнительные операции, которые зависят от харак­теристик полного типа, как этого требуют правила, применимые к состав­ному типу (например, операция < описана для одномерного индексируе­мого типа, если полный тип является дискретным). Эти дополнительные операции считаются неявно описанными в самом начале непосредственной области действия составного типа, их использование разрешено только пос­ле полного описания типа.

Те же правила относятся к операциям, которые неявно описаны для ссылочного типа, чье указание типа есть личный тип или тип, описанный по­средством неполного описания типа.

Для каждого личного типа или подтипа Т определен следующий ат­рибут:

T'CONSTRAINED Вырабатывает значение FALSE, если Т обозначает не­ограниченный личный тип с дискриминантами, не являющийся формальным параметром настройки; вырабатывает также значение FALSE, если Т обо­значает личный тип, являющийся формальным параметром настройки, а соответствующий подтип фактического параметра является либо неограни­ченным типом с дискриминантом, либо неограниченным индексируемым типом; в остальных случаях вырабатывает значение TRUE. Значение атрибу­та имеет предопределенный тип BOOLEAN.

Примечание. Описание личного типа и соответствующее полное описание типа оп­ределяют два разных аспекта одного и того же типа. Вне пакета тип обладает теми ха­рактеристиками, которые определены в видимой части. Для внешних программных модулей тип является как раз личным типом, и любое правило языка, которое приме­няется только к другому классу типов, к этому типу не применимо. Тот факт, что полное описание может реализовать личный тип в виде типа конкретного класса (на­пример, в виде индексируемого типа), можно использовать только внутри пакета.

Последствия такой фактической реализации сказываются, тем не менее, везде. Например, производится некоторая инициализация компонентов по умолчанию; атри­бут SIZE вырабатывает размер полного типа; правила зависимости задач распростра­няются также на компоненты - объекты задачного типа.

Пример:

package УПРАВЛЕНИЕ_ПО_КЛЮЧУ is

type КЛЮЧ is private;

НУЛЕВОЙ _КЛЮЧ: constant КЛЮЧ;

procedure УСТАНОВИТЬ_КЛЮЧ (К: out КЛЮЧ);

function ”<” (X, Y: КЛЮЧ) return BOOLEAN;

private

type КЛЮЧ is new NATURAL;

НУЛЕВОЙ_КЛЮЧ: constant КЛЮЧ: = 0;

end;

package body УПРАВЛЕНИЕ_ПО_КЛЮЧУ is

ПОСЛЕДНИЙ_КЛЮЧ: КЛЮЧ: = 0;

procedure УСТАНОВИТЬ_КЛЮЧ (К: out КЛЮЧ) is begin

ПОСЛЕДНИЙ _КЛЮЧ: = ПОСЛЕДНИЙ _КЛЮЧ + 1;

К: = ПОСЛЕДНИЙ _КЛЮЧ;

end УСТАНОВИТЬ_КЛЮЧ;

function ”<” (X, Y: КЛЮЧ) return BOOLEAN is

begin

return INTEGER (X) < INTEGER (Y);

end ”<”;

end УПРАВЛЕНИЕ_ПО_КЛЮЧУ;

Примечание к примеру. Операциями, применимыми к объектам типа КЛЮЧ вне пакета УПРАВЛЕНИЕ_ПО_КЛ1рЧУ, являются: присваивание, сравнение на равенство и неравенство, процедура УСТАНОВИТЬ_,КЛЮЧ и операция сюда не включаются другие операции отношения, например, ”>=” или арифметические операции.

Явно описанная операция ”<” скрывает предопределенную операцию ”<”, неявно описанную полным описанием типа. В теле функции необходимо явное преобразова­ние X и Y к типу INTEGER для явного вызова операции ”<” для этого типа. С другой стороны, результат функции мог бы быть записан в виде not (X >= Y), так как операция ”>=” не переопределена.

Значение переменной ПОСЛЕДНИЙ_КЛЮЧ, описанной в теле пакета, не меняется между вызовами процедуры УСТАНОВИТЬ_КЛЮЧ (см. также примечание в разд. 7.3).

  1. Субконстанты

Если описание субконстанты дается в видимом разделе пакета, то опи­сание константы (т. е. описание объекта, задающее константу с явной ини­циализацией) с тем же самым идентификатором должно быть элементом описания личного раздела этого пакета. Такое описание объекта называется полным описанием субконстанты. Заданное в полном описании обозначение типа должно быть согласовано с обозначением типа, заданным в описании субконстанты (см. 6.3.1) . Допускаются групповые и единичные полные описания и описания субконстант при условии, что эквивалентные единич­ные описания согласованы.

В спецификации пакета, сйдержащей описание субконстанты, и до кон­ца соответствующего полного описания имя субконстанты допускается ис­пользовать только в выражении по умолчанию для именуемого компонента или формального параметра (но не формального параметра настройки).

Предвыполнение описания субконстанты не дает другого эффекта.

Выполнение программы ошибочно, если оно пытается использовать зна­чение субконстанты до предвыполнения соответствующего полного опи­сания.

Примечание. Полное описание субконстанты заданного личного типа не должно встречаться до соответствующего полного описания типа. Это является следствием правил, определяющих допустимые использования имени, обозначающего личный тип (см. 7.4.1).

  1. Лимитируемые типы

Лимитируемый тип — это тип, для которого неявным описанием не вво­дится ни присваивание, ни сравнение на равенство и неравенство.

Описание личного типа с зарезервированным словом limited описывает лимитируемый тип. Задачный тип является лимитируемым типом. Произ­водный тип от лимитируемого типа сам является лимитируемым типом. На­конец, составной тип является лимитируемым, если тип одного из его ком­понентов является лимитируемым.

Над личным лимитируемым типом определены операции, которые даны в разд. 7.4.2, за исключением присваивания и предопределенного сравнения на равенство и неравенство.

Вид out допустим для формального параметра лимитируемого типа в явно описанной подпрограмме только в том случае, если этот тип является личным лимитируемым типом, а описание подпрограммы находится в види­мом разделе пакета, где описан и личный тип. То же самое относится к фор­мальным параметрам описаний входов и описаний настраиваемых проце­дур. Соответствующий полный тип не должен быть лимитируемым, если хо­тя бы один такой формальный параметр имеет вид out. В противном случае, в качестве соответствующего полного типа допускается (но не требуется) лимитируемый тип (в частности, допустим задачный тип). Если полный тип, соответствующий лимитируемому типу, сам не является лимитируемым, то для этого типа в пакете (но не вне его) допустимо присваивание.

Из правил для лимитируемых типов вытекает следующее:

  • Если тип объекта является лимитируемым, то в описании этого объек­та явная инициализация недопустима.

  • Если тип именуемого компонента является лимитируемым, то выра­жение по умолчанию в описании компонента недопустимо.

  • Если тип объекта, указанного ссылочным типом, является лимитируе­мым, то в генераторе явная инициализация недопустима.

  • Формальный параметр настройки вида in не должен быть лимитируе­мого типа.

Примечание. Описанные выше правила не исключают выражение по умолчанию для формального параметра лимитируемого типа; они не исключают также субконс­танту лимитируемого типа, если полный тип не является лимитируемым. Для лимити­руемого типа допускается явное описание операции равенства (см. 6.7).

Для лимитируемого составного типа не разрешаются агрегаты (см. 3.6.2 и 3.7.4). Для лимитируемого индексируемого типа не разрешается катенация (см. 3.6.2).

Пример:

package ПАКЕТ_ВВОДА_ВЫВОДА is

type ИМЯ_ФАЙЛА is limited private;

procedure ОТКРЫТЬ (F: in out ИМЯ_ФАЙЛА);

procedure ЗАКРЫТЬ (F: in out ИМЯ_ФАЙЛА);

procedure ЧИТАТЬ (F: in ИМЯ_ФАЙЛА; ЭЛЕМЕНТ: out INTEGER);

procedure ПИСАТЬ (F: in ИМЯ_ФАЙЛА; ЭЛЕМЕНТ: in INTEGER);

private

type ИМЯ „ФАЙЛА is

record

ВНУТРЕННЕЕ_ИМЯ: INTEGER: =0;

end record;

end ПАКЕТ_ВВОДА„ВЫВОДА;

package body ПАКЕТ_ВВОДА„ВЫВОДА is

ПРЕДЕЛ: constant: = 200; '

type ДЕСКРИПТОР_ФАЙЛА is record .,. end record;

СПРАВОЧНИК: array (1. .ПРЕДЕЛ) of ДЕСКРИПТОР „ФАЙЛА;

procedure ОТКРЫТЬ (F: in out ИМЯ -ФАЙЛА) is... end;

procedure ЗАКРЫТЬ (F: in out ИМЯ „ФАЙЛА) is ... end;

procedure ЧИТАТЬ (F: in ИМЯ„ФАЙЛА; ЭЛЕМЕНТ: out INTEGER) is ... end;

procedure ПИСАТЬ (F; in ИМЯ_ФАЙЛА; ЭЛЕМЕНТ: in INTEGER) is ... end; begin

end ПАКЕТ_ВВОДА_ВЫВОДА;

Примечание к примеру. В приведенном примере для внешних подпрограмм, ис­пользующих ПАКЕТ_ВВО ДА „ВЫВОД А, имя файла можно получить в результате вы­зова процедуры ОТКРЫТЬ, а затем использовать его в вызовах процедур ЧИТАТЬ и ПИСАТЬ. Следовательно, вне пакета имя файла, полученное после вызова процедуры

ОТКРЫТЬ, выполняет функцию пароля; его внутренние свойства (например, содер­жать числовое значение) неизвестны и никакие другие операции (такие как сложение или сравнение внутренних имен) над этим именем не могут выполняться.

Этот пример характерен для тех случаев, когда желателен полный контроль над операциями. Такие пакеты служат двум целям: они препятствуют пользователю в ис­пользовании внутренней структуры типа; а также реализуют понятие упрятывания (скрытия) типа данных, для которого определены только заданные в спецификации пакета операции.

  1. Пример пакета работы с таблицами

Следующий пример иллюстрирует использование пакетов для организа­ции простого взаимодействия пользователя с довольно сложными процеду­рами.

Необходимо создать пакет для работы с таблицами по внесению и из­влечению их элементов. Элементы включаются в таблицу по мере их по­ступления. Каждый поступивший элемент имеет порядковый номер. Эле­менты выбираются в соответствии с их порядковыми номерами, причем первым выбирается элемент с наименьшим порядковым номером.

С точки зрения пользователя пакет чрезвычайно прост. Существует тип с именем ЭЛЕМЕНТ - тип элемента таблицы, есть процедура ВНЕСТИ для включения элементов в таблицу и процедура ВЫБРАТЬ для извлечения эле­мента с наименьшим порядковым номером. Если таблица пуста, то возвра­щается специальный элемент НУЛЕВОЙ_ЭЛЕМЕНТ, а если таблица запол­нена, то при вызове процедуры ВНЕСТИ возбуждается исключение ТАБЛИ- ЦА_ПЕРЕПОЛНЕНА.

Ниже приведена схема такого пакета. Пользователю известна только спецификация пакета.

package УПРАВЛЕНИЕ_ТАБЛИЦЕЙ is

type ЭЛЕМЕНТ is

record

ПОРЯДКОВЫЙ_НОМЕР: INTEGER;

КОД_ЭЛЕМЕНТА: INTEGER;

КОЛИЧЕСТВО: INTEGER;

ТИП_ЭЛЕМЕНТА:CHARACTER;

end record;

НУЛЕВОЙ-ЭЛЕМЕНТ: constant ЭЛЕМЕНТ: =

(ПОРЯДКОВЫЙ_НОМЕР I КОД_ЭЛЕМЕНТА | КОЛИЧЕСТВО => О, ТИП_ЭЛЕМЕНТА => ");

procedure ВНЕСТИ (НОВЫЙ ЭЛЕМЕНТ: in ЭЛЕМЕНТ);

procedure ВЫБРАТЬ (ПЕРВЫЙ_ЭЛЕМЕНТ: out ЭЛЕМЕНТ) ;

ТАБЛИЦА_ПЕРЕПОЛНЕНА: exception;

  1. - это исключение возбуждается в процедуре ВНЕСТИ, если таблица заполнена end;

Детали реализации таких пакетов могут быть достаточно сложными; в данном случае используются двусвязные списки внутренних элементов. Ло­кальная вспомогательная процедура ИЗМЕНИТЬ используется для переме­щения внутренних элементов из списка занятых в список свободных. На­чальные связи таблицы устанавливаются в разделе инициализации. Нет необ­ходимости показывать пользователям тело пакета.

package body УПРАВЛЕНИЕ_ТАБЛИЦЕЙ is

РАЗМЕР: constant: = 2000;

subtype ИНДЕКС is INTEGER range 0. РАЗМЕР;

type ВНУТРЕННИЙ.ЭЛЕМЕНТ is record

СОДЕРЖИМОЕ: ЭЛЕМЕНТ;

ПОСЛЕДУЮЩИЙ; ИНДЕКС;

ПРЕДЫДУЩИЙ: ИНДЕКС;

end record;

ТАБЛИЦА: array (ИНДЕКС) of ВНУТРЕННИЙ.ЭЛЕМЕНТ;

ПЕРВЫЙ.ЗАНЯТЫЙ.ЭЛЕМЕНТ: ИНДЕКС: = 0;

ПЕРВЫЙ.СВОБОДНЫЙ.ЭЛЕМЕНТ: ИНДЕКС: = 1;

function СПИСОК.СВОБОДНЫХ.ЭЛЕМЕНТОВ.ПУСТ return BOOLEAN is.. .end;

function СПИСОК.ЗАНЯТЫХ.ЭЛЕМЕНТОВ.ПУCT return BOOLEAN is.. .end;

procedure ИЗМЕНИТЬ (ИЗ: in ИНДЕКС; К: in ИНДЕКС) is ... end;

procedure ВНЕСТИ (НОВЫЙ.ЭЛЕМЕНТ: in ЭЛЕМЕНТ) is

begin

if СПИСОК.СВОБОДНЫХ.ЭЛЕМЕНТОВ.ПУСТ then

raise ТАБЛИЦА .ПЕРЕПОЛНЕНА;

end if;

- - остальная часть кода подпрограммы ВНЕСТИ

end ВНЕСТИ;

procedure ВЫБРАТЬ (ПЕРВЫЙ .ЭЛЕМЕНТ: out ЭЛЕМЕНТ) is ... end;

begin

- - инициализация связей таблицы

end УПРАВЛЕНИЕ.ТАБЛИЦЕЙ;

7.6. Пример пакета обработки текстов

Этот пример иллюстрирует простой пакет обработки текстов. Пользова­тели имеют доступ только к видимому разделу; реализация от них скрыта в личном разделе и в теле пакета (тело не показано) .

С точки зрения пользователя ТЕКСТ является строкой переменной дли- • ны. Каждый текстовый объект имеет максимальную длину, которая долж­на задаваться при описании этого объекта, и текущую длину, которая равна длине в диапазоне от нуля до максимального. Максимальная возможная длина текстового объекта является константой, определяемой реализацией.

Сначала в пакете определяются необходимые типы, затем функции, воз­вращающие некоторые характеристики объектов типа, затем функции пре­образования текстов и предопределенных типов CHARACTER и STRING и, наконец, некоторые стандартные операции над переменными строками. Большинство операций над строками, символами, а также над типом ТЕКСТ, совмещены для минимизации числа явных преобразований, которые дол­жен написать пользователь.

package ОБРАБОТКА.ТЕКСТА is

МАКСИМУМ: constant: = НЕКОТОРОЕ.ЗНАЧЕНИЕ;

- - это значение определено реализацией

subtype ИНДЕКС is INTEGER range 0. .МАКСИМУМ;

type ТЕКСТ (МАКСИМАЛЬНАЯ .ДЛИНА: ИНДЕКС) is limited private;

function ДЛИНА (T: ТЕКСТ) return ИНДЕКС;

function ЗНАЧЕНИЕ (Т: ТЕКСТ) return STRING;

function ПУСТО (Т: ТЕКСТ) return BOOLEAN;

function К.ТЕКСТУ (S: STRING; МАКС: ИНДЕКС) return ТЕКСТ;

  • - МАКС - максимальная длина

function К.ТЕКСТУ (С: CHARACTER; МАКС: ИНДЕКС) return ТЕКСТ;

  • unction К„ТЕКСТУ (S: STRING) return ТЕКСТ;

  • - S'LENGTH - максимальная длина

function К_ТЕКСТУ (С: CHARACTER) return ТЕКСТ;

function”*” (СЛЕВА: ТЕКСТ; СПРАВА: ТЕКСТ) return ТЕКСТ;

function ”&” (СЛЕВА: ТЕКСТ; СПРАВА: STRING) return ТЕКСТ;