This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
[ A composite type (other than an array or interface type) can have discriminants, which parameterize the type. A
known_discriminant_part specifies the discriminants of a composite type. A discriminant of an object is a component of the object, and is either of a discrete type or an access type. An
unknown_discriminant_part in the declaration of a view of a type specifies that the discriminants of the type are unknown for the given view; all subtypes of such a view are indefinite subtypes.]
discriminant_partof (<>) is used to indicate unknown discriminants.
Language Design Principles
allocatorappears as a constraint on an access discriminant in a
subtype_indicationthat is elaborated independently from object creation, no such connection exists. For example, if a named constrained subtype is declared via "subtype Constr is Rec(Acc_Discrim => new T);" or if such an
allocatorappears in the
subtype_indicationfor a component, the allocator is evaluated when the
subtype_indicationis elaborated, and hence its lifetime is typically longer than the objects or components that will later be subject to the constraint. In these cases, the allocated object should not be reclaimed until the
subtype_indicationgoes out of scope.
Name Resolution Rules8
The expected type for the
default_expression of a
discriminant_specification is that of the corresponding discriminant.
discriminant_part is only permitted in a declaration for a composite type that is not an array or interface type [(this includes generic formal types)]. A type declared with a
known_discriminant_part is called a discriminated type, as is a type that inherits (known) discriminants.
unknown_discriminant_part. This seems consistent with Ada 83, where such types (in a generic formal part) would not be considered discriminated types. Furthermore, the full type for a type with unknown discriminants need not even be composite, much less have any discriminants.
unknown_discriminant_parts cannot be applied to type declarations that cannot have a
known_discriminant_part. There is no point in having unknown discriminants on a type that can never have discriminants (for instance, a formal modular type), even when these are allowed syntactically.
The subtype of a discriminant may be defined by an optional
null_exclusion and a
subtype_mark, in which case the
subtype_mark shall denote a discrete or access subtype, or it may be defined by an
access_definition. A discriminant that is defined by an
access_definition is called an access discriminant and is of an anonymous access type.
Default_expressions shall be provided either for all or for none of the discriminants of a
default_expressions are permitted in a
known_discriminant_part in a declaration of a nonlimited tagged type [or a generic formal type].
discriminant_specification for an access discriminant may have a
default_expression only in the declaration for an immutably limited type (see 7.5). In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit.
- If a type has an access discriminant, this automatically makes it limited, just like having a limited component automatically makes a type limited. This was rejected because it decreases program readability, and because it seemed error prone (two bugs in a previous version of the RM9X were attributable to this rule).
- A type with an access discriminant shall be limited. This is equivalent to the rule we actually chose for Ada 95, except that it allows a type to have an access discriminant if it is limited just because of a limited component. For example, any record containing a task would be allowed to have an access discriminant, whereas the actual rule requires “limited record”. This rule was also rejected due to readability concerns, and because would interact badly with the rules for limited types that “become nonlimited”.
- A type may have an access discriminant if it is an immutably limited type. This was the rule chosen for Ada 95.
- Any type may have an access discriminant. For nonlimited type, there is no special accessibility for access discriminants; they're the same as any other anonymous access component. For a limited type, they have the special accessibility of Ada 95. However, this doesn't work because a limited partial view can have a nonlimited full view -- giving the two views different accessibility.
- Any type may have an access discriminant, as above. However, special accessibility rules only apply to types that are immutably limited (task, protected, and explicitly limited records). However, this breaks privacy; worse, Legality Rules depend on the definition of accessibility.
- Any type may have an access discriminant, as above. Limited types have special accessibility, while nonlimited types have normal accessibility. However, a limited partial view with an access discriminant can only be completed by an immutably limited type. That prevents accessibility from changing. A runtime accessibility check is required on generic formal types with access discriminants. However, changing between limited and nonlimited types would have far-reaching consequences for access discriminants — which is uncomfortable.
- Any type may have an access discriminant. All types have special accessibility. This was considered early during the Ada 9X process, but was dropped for “unpleasant complexities”, which unfortunately aren't recorded. It does seem that an accessibility check would be needed on assignment of such a type, to avoid copying an object with a discriminant pointing to a local object into a more global object (and thus creating a dangling pointer).
- Any type may have an access discriminant, but access discriminants cannot have defaults. All types have special accessibility. This gets rid of the problems on assignment (you couldn't change such a discriminant), but it would be horribly incompatible with Ada 95.
- Any type may have an access discriminant, but access discriminants may have defaults only if they are of an immutably limited type. This is the rule chosen for Ada 2005, as it is not incompatible, and it doesn't require weird accessibility checks.
This paragraph was deleted.
For a type defined by a
derived_type_definition, if a
known_discriminant_part is provided in its declaration, then:
- The parent subtype shall be constrained;
- If the parent type is not a tagged type, then each discriminant of the derived type shall be used in the constraint defining the parent subtype;
- If a discriminant is used in the constraint defining the parent subtype, the subtype of the discriminant shall be statically compatible (see 4.9.1) with the subtype of the corresponding parent discriminant.
default_expressionas the parent's discriminant.
This paragraph was deleted.
discriminant_specification declares a discriminant; the
subtype_mark denotes its subtype unless it is an access discriminant, in which case the discriminant's subtype is the anonymous access-to-variable subtype defined by the
[For a type defined by a
derived_type_definition, each discriminant of the parent type is either inherited, constrained to equal some new discriminant of the derived type, or constrained to the value of an expression.] When inherited or constrained to equal some new discriminant, the parent discriminant and the discriminant of the derived type are said to correspond. Two discriminants also correspond if there is some common discriminant to which they both correspond. A discriminant corresponds to itself as well. If a discriminant of a parent type is constrained to a specific value by a
derived_type_definition, then that discriminant is said to be specified by that
constraint that appears within the definition of a discriminated type depends on a discriminant of the type if it names the discriminant as a bound or discriminant value. A
component_definition depends on a discriminant if its
constraint depends on the discriminant, or on a discriminant that corresponds to it.
task_bodyis not considered to depend on a discriminant of the task type, even if it names it. It is only the
constraints in the type definition itself that are considered dependents. Similarly for protected types.
A component depends on a discriminant if:
component_definitiondepends on the discriminant; or
default_expressionrefers to the discriminant.
- It is declared in a
variant_partthat is governed by the discriminant; or 24
- It is a component inherited as part of a
derived_type_definition, and the
constraintof the parent_
subtype_indicationdepends on the discriminant; or
known_discriminant_partwhose discriminants are used to constrain the old discriminants.
- It is a subcomponent of a component that depends on the discriminant.
Each value of a discriminated type includes a value for each component of the type that does not depend on a discriminant[; this includes the discriminants themselves]. The values of discriminants determine which other component values are present in the value of the discriminated type.
derived_type_definition. That's why we say "values of discriminants" instead of "values of the discriminants" — a subtle point.
A type declared with a
known_discriminant_part is said to have known discriminants; its first subtype is unconstrained. A type declared with an
unknown_discriminant_part is said to have unknown discriminants. A type declared without a
discriminant_part has no discriminants, unless it is a derived type; if derived, such a type has the same sort of discriminants (known, unknown, or none) as its parent (or ancestor) type. A tagged class-wide type also has unknown discriminants. [Any subtype of a type with unknown discriminants is an unconstrained and indefinite subtype (see 3.2 and 3.3).]
unknown_discriminant_part“(<>)” is only permitted in the declaration of a (generic or nongeneric) private type, private extension, incomplete type, or formal derived type. Hence, only such types, descendants thereof, and class-wide types can have unknown discriminants. An
unknown_discriminant_partis used to indicate that the corresponding actual or full type might have discriminants without defaults, or be an unconstrained array subtype. Tagged class-wide types are also considered to have unknown discriminants because discriminants can be added by type extensions, so the total number of discriminants of any given value of a tagged class-wide type is not known at compile time.
For an access discriminant, its
access_definition is elaborated when the value of the access discriminant is defined: by evaluation of its
default_expression, by elaboration of a
discriminant_constraint, or by an assignment that initializes the enclosing object.
expressiondefining the access discriminant to the anonymous access type raises Program_Error for an object created by an allocator of an access type T, if the initial value is an access parameter that designates a view whose accessibility level is deeper than that of T.
default_expressions for its discriminants, then unconstrained variables of the type are permitted, and the values of the discriminants can be changed by an assignment to such a variable. If defaults are not provided for the discriminants, then all variables of the type are constrained, either by explicit constraint or by their initial value; the values of the discriminants of such a variable cannot be changed after initialization.
default_expressionfor a discriminant of a type is evaluated when an object of an unconstrained subtype of the type is created.
assignment_statements nor assignments inherent in passing as an in out or out parameter are allowed. Note however that the value of a discriminant can be changed by assigning to the enclosing object, presuming it is an unconstrained variable.
unknown_discriminant_partis permitted only in the declaration of a private type (including generic formal private), private extension, incomplete type, or generic formal derived type. These are the things that will have a corresponding completion or generic actual, which will either define the discriminants, or say there are none. The (<>) indicates that the actual/full subtype might be an indefinite subtype. An
unknown_discriminant_partis not permitted in a normal untagged derived type declaration, because there is no separate full type declaration for such a type. Note that (<>) allows unconstrained array bounds; those are somewhat like undefaulted discriminants.
discriminant_part. In this latter case, each discriminant of the parent type shall be constrained, either to a specific value, or to equal one of the new discriminants. Constraining a parent type's discriminant to equal one of the new discriminants is like a renaming of the discriminant, except that the subtype of the new discriminant can be more restrictive than that of the parent's one. In any case, the new discriminant can share storage with the parent's discriminant.
Examples of discriminated types:
type Buffer(Size : Buffer_Size := 100) is -- see 3.5.4 record Pos : Buffer_Size := 0; Value : String(1 .. Size); end record; 35type Matrix_Rec(Rows, Columns : Integer) is record Mat : Matrix(1 .. Rows, 1 .. Columns); -- see 3.6 end record; 36type Square(Side : Integer) is new Matrix_Rec(Rows => Side, Columns => Side); 37type Double_Square(Number : Integer) is record Left : Square(Number); Right : Square(Number); end record; 38/3task type Worker(Prio : System.Priority; Buf : access Buffer) with Priority => Prio is -- see D.1 -- discriminants used to parameterize the task type (see 9.1) entry Fill; entry Drain; end Worker;
Extensions to Ada 83
discriminant_specificationis modified to allow an access discriminant, with a type specified by an
Discriminant_parts are not elaborated, though an
access_definitionis elaborated when the discriminant is initialized.
Extensions to Ada 95
null_exclusioncan be used in the declaration of a discriminant.
Wording Changes from Ada 95
Incompatibilities With Ada 2005
Extensions to Ada 2005
Extensions to Ada 2012
aspect_specification, allowing the specification of (implementation-defined) aspects for individual discriminants.
3.7.1 Discriminant Constraints1
discriminant_constraint specifies the values of the discriminants for a given discriminated type.
Language Design Principles
discriminant_association is said to be named if it has one or more discriminant_
selector_names; it is otherwise said to be positional. In a
discriminant_constraint, any positional associations shall precede any named associations.
Name Resolution Rules5
selector_name of a named
discriminant_association shall resolve to denote a discriminant of the subtype being constrained; the discriminants so named are the associated discriminants of the named association. For a positional association, the associated discriminant is the one whose
discriminant_specification occurred in the corresponding position in the
known_discriminant_part that defined the discriminants of the subtype being constrained.
The expected type for the
expression in a
discriminant_association is that of the associated discriminant(s).
discriminant_constraint is only allowed in a
subtype_mark denotes either an unconstrained discriminated subtype, or an unconstrained access subtype whose designated subtype is an unconstrained discriminated subtype. However, in the case of an access subtype, a
discriminant_constraint is legal only if any dereference of a value of the access type is known to be constrained (see 3.3). In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit.
discriminant_association with more than one
selector_name is allowed only if the named discriminants are all of the same type. A
discriminant_constraint shall provide exactly one value for each discriminant of the subtype being constrained.
This paragraph was deleted.
expressionassociated with an access discriminant is convertible (see 4.6) to the anonymous access type. This implies both convertibility of designated types, and static accessibility. This implies that if an object of type T with an access discriminant is created by an allocator for an access type A, then it requires that the type of the
expressionassociated with the access discriminant have an accessibility level that is not statically deeper than that of A. This is to avoid dangling references.
discriminant_constraint is compatible with an unconstrained discriminated subtype if each discriminant value belongs to the subtype of the corresponding discriminant.
A composite value satisfies a discriminant constraint if and only if each discriminant of the composite value has the value imposed by the discriminant constraint.
For the elaboration of a
expressions in the
discriminant_associations are evaluated in an arbitrary order and converted to the type of the associated discriminant (which can raise Constraint_Error — see 4.6); the
expression of a named association is evaluated (and converted) once for each associated discriminant. The result of each evaluation and conversion is the value imposed by the constraint for the associated discriminant.
Examples (using types declared above in subclause 3.7):
Large : Buffer(200); -- constrained, always 200 characters
-- (explicit discriminant value)
Message : Buffer; -- unconstrained, initially 100 characters
-- (default discriminant value)
Basis : Square(5); -- constrained, always 5 by 5
Illegal : Square; -- illegal, a Square has to be constrained
Inconsistencies With Ada 83
Incompatibilities With Ada 95
discriminant_constraints for general access subtypes. Such constraints are prohibited if the designated type can be treated as constrained somewhere in the program. Ada 2005 goes further and prohibits such
discriminant_constraints if the designated type has (or might have, in the case of a formal type) defaults for its discriminants. The use of general access subtypes is rare, and this eliminates a boatload of problems that required many restrictions on the use of aliased objects and components (now lifted). Similarly, Ada 2005 prohibits
discriminant_constraints on any access type whose designated type has a partial view that is constrained. Such a type will not be constrained in the heap to avoid privacy problems. Again, the use of such subtypes is rare (they can only happen within the package and its child units).
3.7.2 Operations of Discriminated Types1
[If a discriminated type has
default_expressions for its discriminants, then unconstrained variables of the type are permitted, and the discriminants of such a variable can be changed by assignment to the variable. For a formal parameter of such a type, an attribute is provided to determine whether the corresponding actual parameter is constrained or unconstrained.]
prefix A that is of a discriminated type [(after any implicit dereference)], the following attribute is defined:
- Yields the value True if A denotes a constant, a value, a tagged object, or a constrained variable, and False otherwise. The value of this attribute is of the predefined type Boolean.
The execution of a construct is erroneous if the construct has a constituent that is a
name denoting a subcomponent that depends on discriminants, and the value of any of these discriminants is changed by this execution between evaluating the
name and the last use (within this execution) of the subcomponent denoted by the
assignment_statements, calls (except when the discriminant-dependent subcomponent is an in parameter passed by copy),
slices. Ada 83 only covered the first two cases. AI83-00585 pointed out the situation with the last two cases. The cases of
object_renaming_declarations and generic formal in out objects are handled differently, by disallowing the situation at compile time.
Extensions to Ada 83
prefixof Constrained to be a value as well as an object of a discriminated type, and also an implicit dereference. These extensions are not important capabilities, but there seems no reason to make this attribute different from other similar attributes. We are curious what most Ada 83 compilers do with F(1).X'Constrained.
sliceis discriminant-dependent, and the evaluation of the index or discrete range changes the value of a discriminant.
names that denote discriminant-dependent subcomponents to this subclause. In Ada 83, it used to appear separately under
assignment_statements and subprogram calls.