Справочник по Ada (Ada 2022)
3.7 Дискриминанты
Тип-композит (кроме массива или интерфейсного типа) может иметь дискриминанты, которые параметризуют тип. known_discriminant_part определяет дискриминанты типа-композита. Дискриминант объекта — это компонент объекта, и он является либо дискретного типа, либо типа доступа. unknown_discriminant_part в объявлении представления типа указывает, что дискриминанты типа неизвестны для данного представления; все подтипы такого представления являются неопределёнными подтипами.
Синтаксис
unknown_discriminant_part ::= (<>)
discriminant_specification ::=
defining_identifier_list : [null_exclusion] subtype_mark [:= default_expression]
[aspect_specification]
| defining_identifier_list : access_definition [:= default_expression]
[aspect_specification]
defining_identifier_list : [null_exclusion] subtype_mark [:= default_expression]
[aspect_specification]
| defining_identifier_list : access_definition [:= default_expression]
[aspect_specification]
Правила разрешения имён
Ожидаемый тип для default_expression в discriminant_specification соответствует типу соответствующего дискриминанта.
Правила легальности
Раздел discriminant_part допускается только в объявлении типа-композита, который не является массивом или интерфейсным типом (включая формальные типы-параметры обобщений). Тип, объявленный с known_discriminant_part, называется дискриминированным типом, так же как и тип, который наследует (известные) дискриминанты.
Подтип дискриминанта может быть определён с помощью необязательного null_exclusion и subtype_mark, в этом случае subtype_mark должен обозначать дискретный или тип доступа подтип, или он может быть определён с помощью access_definition. Дискриминант, определённый с помощью access_definition, называется дискриминантом доступа и является анонимного типа доступа.
Значения default_expression должны быть предоставлены либо для всех, либо для ни одного из дискриминантов в known_discriminant_part. В known_discriminant_part в объявлении не ограниченного тегированного типа или формального типа обобщения значения default_expression не допускаются.
discriminant_specification для дискриминанта доступа может иметь default_expression только в объявлении неизменяемого ограниченного типа (см. 7.5). Помимо мест, где обычно применяются Правила легальности (см. 12.3), это правило применяется также в приватной части экземпляра обобщённого блока.
Этот абзац был удалён.
Для типа, определённого derived_type_definition, если в его объявлении указан known_discriminant_part, то:
- Родительский подтип должен быть ограничен;
- Если родительский тип не является тегированным типом, то каждый дискриминант производного типа должен использоваться в ограничении, определяющем родительский подтип;
- Если дискриминант используется в ограничении, определяющем родительский подтип, подтип дискриминанта должен быть статически совместим (см. 4.9.1) с подтипом соответствующего родительского дискриминанта.
Этот абзац был удалён.
Статическая семантика
discriminant_specification объявляет дискриминант; subtype_mark обозначает его подтип, если это не дискриминант доступа, в этом случае подтип дискриминанта — это анонимный подтип доступа к переменной, определённый в access_definition.
Для типа, определённого derived_type_definition, каждый дискриминант родительского типа наследуется, ограничен равенством некоторому новому дискриминанту производного типа или ограничен значением выражения. Если он наследуется или ограничен равенством некоторому новому дискриминанту, то родительский дискриминант и дискриминант производного типа считаются соответствующими. Два дискриминанта также соответствуют, если есть некоторый общий дискриминант, которому они оба соответствуют. Дискриминант соответствует самому себе. Если дискриминант родительского типа ограничен конкретным значением с помощью derived_type_definition, то этот дискриминант считается указанным этим derived_type_definition.
Ограничение, которое появляется в определении дискриминированного типа, зависит от дискриминанта типа, если оно называет дискриминант как границу или значение дискриминанта. component_definition зависит от дискриминанта, если его ограничение зависит от дискриминанта или от дискриминанта, соответствующего ему.
Компонент зависит от дискриминанта, если:
- Его component_definition зависит от дискриминанта; или
- Он объявлен в variant_part, который регулируется дискриминантом; или
- Это компонент, унаследованный в рамках derived_type_definition, и ограничение родительского subtype_indication зависит от дискриминанта; или
- Это подкомпонент компонента, который зависит от дискриминанта.
Каждое значение дискриминированного типа включает значение для каждого компонента типа, который не зависит от дискриминанта; это включает и сами дискриминанты. Значения дискриминантов определяют, какие другие компоненты присутствуют в значении дискриминированного типа.
Тип, объявленный с known_discriminant_part, имеет известные дискриминанты; его первый подтип не ограничен. Тип, объявленный с unknown_discriminant_part, имеет неизвестные дискриминанты. Тип, объявленный без discriminant_part, не имеет дискриминантов, если это не производный тип; если производный, такой тип имеет тот же тип дискриминантов (известные, неизвестные или нет), что и родительский (или предковый) тип. Тип тегированного класса также имеет неизвестные дискриминанты. Любой подтип типа с неизвестными дискриминантами является неограниченным и неопределённым подтипом (см. 3.2 и 3.3).
Динамическая семантика
Для дискриминанта доступа, его access_definition обрабатывается, когда определяется значение дискриминанта доступа: путём оценки его default_expression, путём обработки discriminant_constraint, или присваиванием, инициализирующим окружающий объект.
END_OF_DOCUMENT_MARKER ПРИМЕЧАНИЕ 1 Если у дискриминируемого типа есть default_expression для его дискриминантов, то допускаются неограниченные переменные типа, и значения дискриминантов могут быть изменены присваиванием такой переменной. Если значения по умолчанию не указаны для дискриминантов, то все переменные типа ограничены, либо явным ограничением, либо своим начальным значением; значения дискриминантов такой переменной нельзя изменить после инициализации.
ПРИМЕЧАНИЕ 2 default_expression для дискриминанта типа вычисляется при создании объекта неограниченного подтипа типа.
ПРИМЕЧАНИЕ 3 Присваивание дискриминанту объекта (после его инициализации) запрещено, так как имя дискриминанта является константой; не допускаются ни assignment_statement, ни присваивания, связанные с передачей в качестве параметра in out или out. Однако обратите внимание, что значение дискриминанта может быть изменено присваиванием закрывающему объекту, предполагая, что это неограниченная переменная.
ПРИМЕЧАНИЕ 4 Дискриминант, который является типом именованного доступа, не называется дискриминантом доступа; это понятие используется только для дискриминантов, определенных с помощью access_definition.
Примеры
Примеры дискриминируемых типов:
тип Buffer(Size : Buffer_Size := 100) is -- см. 3.5.4
record
Pos : Buffer_Size := 0;
Value : String(1 .. Size);
end record;
record
Pos : Buffer_Size := 0;
Value : String(1 .. Size);
end record;
тип Matrix_Rec(Rows, Columns : Integer) is
record
Mat : Matrix(1 .. Rows, 1 .. Columns); -- см. 3.6
end record;
record
Mat : Matrix(1 .. Rows, 1 .. Columns); -- см. 3.6
end record;
тип Square(Side : Integer) is new
Matrix_Rec(Rows => Side, Columns => Side);
Matrix_Rec(Rows => Side, Columns => Side);
тип Double_Square(Number : Integer) is
record
Left : Square(Number);
Right : Square(Number);
end record;
record
Left : Square(Number);
Right : Square(Number);
end record;
тип задачи Worker(Prio : System.Priority; Buf : access Buffer)
с Priority => Prio is -- см. D.1
-- дискриминанты используются для параметризации типа задачи (см. 9.1)
вход Fill;
вход Drain;
end Worker;
с Priority => Prio is -- см. D.1
-- дискриминанты используются для параметризации типа задачи (см. 9.1)
вход Fill;
вход Drain;
end Worker;