Справочник по Ada 2012
3.2.4 Предикаты подтипов
Определенные языком предикатные атрибуты Static_Predicate и Dynamic_Predicate могут использоваться для определения свойств подтипов. Спецификация предиката — это спецификация_атрибута для одного из двух предикатов. Общие правила для атрибутов и спецификаций_атрибутов приведены в разделе 13 (13.1 и 13.1.1 соответственно).
Правила разрешения имен
Ожидаемый тип для предикатного атрибута выражение — любой булев тип.
Статическая семантика
Спецификация предиката может быть задана для объявления_типа или объявления_подтипа и применяется к объявленному подтипу. Кроме того, спецификации предикатов применяются к некоторым другим подтипам:
- Для (первичного) подтипа, определенного объявлением типа, любые предикаты родительских или предковых подтипов применяются.
- Для подтипа, созданного с помощью указание_подтипа, применяется предикат подтипа, обозначенного меткой_подтипа.
Этот абзац был удален.
Проверки предикатов определены как активированные или деактивированные для данного подтипа следующим образом:
- Если подтип объявлен с помощью объявления_типа или объявления_подтипа, включающего спецификацию предиката, то:
если выполнение проверок требуется политикой проверки Static_Predicate (см. 11.4.2) и объявление содержит спецификацию Static_Predicate, то проверки предиката активированы для подтипа;
если выполнение проверок требуется политикой проверки Dynamic_Predicate (см. 11.4.2) и объявление содержит спецификацию Dynamic_Predicate, то проверки предиката активированы для подтипа;
в противном случае проверки предикатов деактивированы для подтипа, независимо от того, активированы ли проверки предиката для других подтипов, упомянутых в объявлении;
- Если подтип определяется объявлением типа, не включающим спецификацию предиката, то проверки предикатов активированы для подтипа только в том случае, если проверки предикатов активированы для родительских или предковых подтипов;
- Если подтип создан с помощью указание_подтипа помимо указанных случаев, то проверки предикатов активированы для подтипа только в том случае, если проверки предикатов активированы для подтипа, обозначенного меткой_подтипа;
- В противном случае проверки предикатов деактивированы для данного подтипа.
Для подтипа с непосредственно заданным предикатом может быть указан дополнительный язык-определяемый атрибут с помощью спецификация_атрибута (см. 13.1.1):
Predicate_Failure
Этот атрибут задаётся выражением, который определяет действие, которое должно быть выполнено при неудачной проверке предиката, поскольку напрямую заданный предикат подтипа принимает значение False, как объяснено ниже.
Правила разрешения имен
Ожидаемый тип для выражения Predicate_Failure — String.
Правила допустимости
Выражение спецификации Static_Predicate должно быть предикатно-статическим; то есть одним из следующих:
- статическое выражение;
- проверка членства, где тестируемое_простое_выражение — текущий экземпляр, а список_выбора_членства удовлетворяет требованиям для статической проверки членства (см. 4.9);
- выражение_случая выражение_случая, где выбирающее_выражение — текущий экземпляр, а зависимые_выражения — статические выражения;
- вызов предопределенного оператора равенства или упорядочения, где один операнд — текущий экземпляр, а другой — статическое выражение;
- вызов предопределенного булева оператора and, or, xor или not, где каждый операнд — предикат-статическое;
- форма управления короткого замыкания, где оба операнда — предикат-статические; или
- скобочное предикат-статическое выражение.
Для неполного подтипа предикат не должен быть указан.
Если предикат применяется к подтипу, то этот предикат не должен упоминать ни один другой подтип, к которому применяется тот же предикат.
Индексный подтип, дискретный_диапазон ограничение_индекса или срез, или определение_дискретного_подтипа определение_массива_с_ограничениями, объявление_записи или спецификация_индекса_записи не должны обозначать подтип, к которому применяются спецификации предикатов.
Префикс ссылка_на_атрибут, у которого имя_атрибута — First, Last или Range, не должен обозначать скалярный подтип, к которому применяются спецификации предикатов.
Определение_дискретного_подтипа спецификация_параметра_цикла не должно обозначать нестатический подтип, к которому применяются спецификации предикатов, или любой подтип, к которому применяются спецификации Dynamic_Predicate.
Дискретный_выбор агрегат_массива_с_именами не должен обозначать нестатический подтип, к которому применяются спецификации предикатов.
В дополнение к местам, где обычно применяются правила допустимости (см. 12.3), эти правила применяются также в частях «private» экземпляра генерического блока.
Динамическая семантика
Если какое-либо из вышеперечисленных правил допустимости нарушается в экземпляре генерического блока, то Program_Error возникает в точке нарушения.
Чтобы определить, удовлетворяет ли значение предикатам подтипа S, выполняются следующие проверки в следующем порядке, пока одна из проверок не завершится неудачей, в этом случае предикаты не удовлетворяются и дальнейшие проверки не выполняются, или все проверки завершаются успешно, в этом случае предикаты удовлетворяются:
- Сначала значение проверяется на соответствие ограничениям или исключению нулевого значения подтипа S;
- затем:
если S — первый подтип, значение проверяется на соответствие предикатам родительских и предковых подтипов (если таковые имеются) подтипа S (в произвольном порядке);
если S определен с помощью указание_подтипа, значение проверяется на соответствие предикатам подтипа, обозначенного меткой_подтипа указание_подтипа;
- наконец, если S определен объявлением, к которому применяются одна или несколько спецификаций предикатов, предикаты вычисляются (в произвольном порядке), чтобы проверить, что все они возвращают True для данного значения.
Если проверки предикатов активированы для данного подтипа, то:
При каждом преобразовании подтипа выполняется проверка, удовлетворяет ли операнд предикатам целевого подтипа. Это включает передачу всех параметров, за исключением некоторых параметров, передаваемых по ссылке, которые охватываются следующим правилом: после нормального завершения и выхода из подпрограммы для каждого параметра in out или out, передаваемого по ссылке, выполняется проверка, удовлетворяет ли значение параметра предикатам подтипа фактического. Для объекта, созданного с помощью object_declaration без явной инициализации expression, или с помощью неинициализированного allocator, если какие-либо подкомпоненты имеют default_expressionы, выполняется проверка, удовлетворяет ли значение созданного объекта предикатам номинального подтипа.
Если какая-либо из проверок предикатов завершается неудачно, возникает исключение Assertion_Error, если только подтип, у которого непосредственно указанный аспект предиката имел значение False, не имеет также непосредственно указанного аспекта Predicate_Failure. В этом случае вычисляется указанное выражение Predicate_Failure expression; если вычисление выражения Predicate_Failure expression генерирует исключение, то это исключение передаётся для обозначения неудачи проверки предиката; в противном случае генерируется исключение Assertion_Error с ассоциированной строкой сообщения, определяемой значением выражения Predicate_Failure expression. В отсутствие такого аспекта Predicate_Failure реализация может связать с исключением Assertion_Error строку сообщения с определённым для неё значением.
Этот абзац был удалён.
Этот абзац был удалён.
ПРИМЕЧАНИЯ
5 Указание предиката не приводит к тому, что подтип считается ограниченным.
6 Статический предикат, подобно ограничению, всегда остаётся истинным для всех объектов подтипа, за исключением случаев неинициализированных переменных и других недопустимых значений. Динамический предикат, с другой стороны, проверяется, как указано выше, но может стать ложным в другие моменты. Например, предикат подтипа записи не проверяется при модификации подкомпонента.
7 Никакие предикаты не применяются к базовому подтипу скалярного типа; каждое значение скалярного типа T считается удовлетворяющим предикатам T'Base.
8 Выражения Predicate_Failure expression никогда не вычисляются во время проверки на принадлежность (см. 4.5.2) или атрибута Valid (см. 13.9.2).
Примеры
подтип Basic_Letter is Character -- См. A.3.2 для "базовой буквы".
с Static_Predicate => Basic_Letter in 'A'..'Z' | 'a'..'z' | 'Æ' | 'æ' | 'Ð' | 'ð' | 'Þ' | 'þ' | 'ß';
с Static_Predicate => Basic_Letter in 'A'..'Z' | 'a'..'z' | 'Æ' | 'æ' | 'Ð' | 'ð' | 'Þ' | 'þ' | 'ß';
подтип Even_Integer is Integer
с Dynamic_Predicate => Even_Integer mod 2 = 0,
Predicate_Failure => "Even_Integer должен быть кратным 2";
с Dynamic_Predicate => Even_Integer mod 2 = 0,
Predicate_Failure => "Even_Integer должен быть кратным 2";
Text_IO (см. A.10.1) мог бы использовать предикаты для описания некоторых распространённых исключительных ситуаций следующим образом:
с Ada.IO_Exceptions;
пакет Ada.Text_IO is
пакет Ada.Text_IO is
тип File_Type is limited private;
подтип Open_File_Type is File_Type
с Dynamic_Predicate => Is_Open (Open_File_Type),
Predicate_Failure => raise Status_Error с "Файл не открыт";
подтип Input_File_Type is Open_File_Type
с Dynamic_Predicate => Mode (Input_File_Type) = In_File,
Predicate_Failure => raise Mode_Error с "Невозможно прочитать файл: " &
Name (Input_File_Type);
подтип Output_File_Type is Open_File_Type
с Dynamic_Predicate => Mode (Output_File_Type) /= In_File,
Predicate_Failure => raise Mode_Error с "Невозможно записать файл: " &
Name (Output_File_Type);
с Dynamic_Predicate => Is_Open (Open_File_Type),
Predicate_Failure => raise Status_Error с "Файл не открыт";
подтип Input_File_Type is Open_File_Type
с Dynamic_Predicate => Mode (Input_File_Type) = In_File,
Predicate_Failure => raise Mode_Error с "Невозможно прочитать файл: " &
Name (Input_File_Type);
подтип Output_File_Type is Open_File_Type
с Dynamic_Predicate => Mode (Output_File_Type) /= In_File,
Predicate_Failure => raise Mode_Error с "Невозможно записать файл: " &
Name (Output_File_Type);
...
функция Mode (File : in Open_File_Type) return File_Mode;
функция Name (File : in Open_File_Type) return String;
функция Form (File : in Open_File_Type) return String;
функция Name (File : in Open_File_Type) return String;
функция Form (File : in Open_File_Type) return String;
...
процедура Get (File : in Input_File_Type; Item : out Character);
процедура Put (File : in Output_File_Type; Item : in Character);
...
-- Аналогично для всех других подпрограмм ввода и вывода.