Если составной тип имеет подкомпонент личного типа и описан вне пакета, содержащего описание этого личного типа, то неявно описанные при описании составного типа операции включают все операции, которые зависят только от характеристик, следующих из одного описания личного типа. (Например, операция < не включается в набор операций для одномерного индексируемого типа).
Если составной тип сам описан внутри пакета, содержащего описание личного типа (включая внутренний пакет или настраиваемый пакет), то неявно описываются дополнительные операции, которые зависят от характеристик полного типа, как этого требуют правила, применимые к составному типу (например, операция < описана для одномерного индексируемого типа, если полный тип является дискретным). Эти дополнительные операции считаются неявно описанными в самом начале непосредственной области действия составного типа, их использование разрешено только после полного описания типа.
Те же правила относятся к операциям, которые неявно описаны для ссылочного типа, чье указание типа есть личный тип или тип, описанный посредством неполного описания типа.
Для каждого личного типа или подтипа Т определен следующий атрибут:
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).
Субконстанты
Если описание субконстанты дается в видимом разделе пакета, то описание константы (т. е. описание объекта, задающее константу с явной инициализацией) с тем же самым идентификатором должно быть элементом описания личного раздела этого пакета. Такое описание объекта называется полным описанием субконстанты. Заданное в полном описании обозначение типа должно быть согласовано с обозначением типа, заданным в описании субконстанты (см. 6.3.1) . Допускаются групповые и единичные полные описания и описания субконстант при условии, что эквивалентные единичные описания согласованы.
В спецификации пакета, сйдержащей описание субконстанты, и до конца соответствующего полного описания имя субконстанты допускается использовать только в выражении по умолчанию для именуемого компонента или формального параметра (но не формального параметра настройки).
Предвыполнение описания субконстанты не дает другого эффекта.
Выполнение программы ошибочно, если оно пытается использовать значение субконстанты до предвыполнения соответствующего полного описания.
Примечание. Полное описание субконстанты заданного личного типа не должно встречаться до соответствующего полного описания типа. Это является следствием правил, определяющих допустимые использования имени, обозначающего личный тип (см. 7.4.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 ПАКЕТ_ВВОДА_ВЫВОДА;
Примечание к примеру. В приведенном примере для внешних подпрограмм, использующих ПАКЕТ_ВВО ДА „ВЫВОД А, имя файла можно получить в результате вызова процедуры ОТКРЫТЬ, а затем использовать его в вызовах процедур ЧИТАТЬ и ПИСАТЬ. Следовательно, вне пакета имя файла, полученное после вызова процедуры
ОТКРЫТЬ, выполняет функцию пароля; его внутренние свойства (например, содержать числовое значение) неизвестны и никакие другие операции (такие как сложение или сравнение внутренних имен) над этим именем не могут выполняться.
Этот пример характерен для тех случаев, когда желателен полный контроль над операциями. Такие пакеты служат двум целям: они препятствуют пользователю в использовании внутренней структуры типа; а также реализуют понятие упрятывания (скрытия) типа данных, для которого определены только заданные в спецификации пакета операции.
Пример пакета работы с таблицами
Следующий пример иллюстрирует использование пакетов для организации простого взаимодействия пользователя с довольно сложными процедурами.
Необходимо создать пакет для работы с таблицами по внесению и извлечению их элементов. Элементы включаются в таблицу по мере их поступления. Каждый поступивший элемент имеет порядковый номер. Элементы выбираются в соответствии с их порядковыми номерами, причем первым выбирается элемент с наименьшим порядковым номером.
С точки зрения пользователя пакет чрезвычайно прост. Существует тип с именем ЭЛЕМЕНТ - тип элемента таблицы, есть процедура ВНЕСТИ для включения элементов в таблицу и процедура ВЫБРАТЬ для извлечения элемента с наименьшим порядковым номером. Если таблица пуста, то возвращается специальный элемент НУЛЕВОЙ_ЭЛЕМЕНТ, а если таблица заполнена, то при вызове процедуры ВНЕСТИ возбуждается исключение ТАБЛИ- ЦА_ПЕРЕПОЛНЕНА.
Ниже приведена схема такого пакета. Пользователю известна только спецификация пакета.
package УПРАВЛЕНИЕ_ТАБЛИЦЕЙ is
type ЭЛЕМЕНТ is
record
ПОРЯДКОВЫЙ_НОМЕР: INTEGER;
КОД_ЭЛЕМЕНТА: INTEGER;
КОЛИЧЕСТВО: INTEGER;
ТИП_ЭЛЕМЕНТА:CHARACTER;
end record;
НУЛЕВОЙ-ЭЛЕМЕНТ: constant ЭЛЕМЕНТ: =
(ПОРЯДКОВЫЙ_НОМЕР I КОД_ЭЛЕМЕНТА | КОЛИЧЕСТВО => О, ТИП_ЭЛЕМЕНТА => ");
procedure ВНЕСТИ (НОВЫЙ ЭЛЕМЕНТ: in ЭЛЕМЕНТ);
procedure ВЫБРАТЬ (ПЕРВЫЙ_ЭЛЕМЕНТ: out ЭЛЕМЕНТ) ;
ТАБЛИЦА_ПЕРЕПОЛНЕНА: exception;
- это исключение возбуждается в процедуре ВНЕСТИ, если таблица заполнена 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 ТЕКСТ;