3.2 Types and Subtypes
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
A type is characterized by a set of values, and a set of primitive operations which implement the fundamental aspects of its semantics. An object of a given type is a run-time entity that contains (has) a value of the type.
Types are grouped into categories of types. There exist several language-defined categories of types (see NOTES below), reflecting the similarity of their values and primitive operations. [Most categories of types form classes of types.] Elementary types are those whose values are logically indivisible; composite types are those whose values are composed of component values.
case_statements and as array indices.
The elementary types are the scalar types (discrete and real) and the access types (whose values provide access to objects or subprograms). Discrete types are either integer types or are defined by enumeration of their values (enumeration types). Real types are either floating point types or fixed point types.
The composite types are the record types, record extensions, array types, interface types, task types, and protected types.
There can be multiple views of a type with varying sets of operations. [An incomplete type represents an incomplete view (see 3.10.1) of a type with a very restricted usage, providing support for recursive data structures. A private type or private extension represents a partial view (see 7.3) of a type, providing support for data abstraction. The full view (see 3.2.1) of a type represents its complete definition.] An incomplete or partial view is considered a composite type[, even if the full view is not].
Certain composite types (and views thereof) have special components called discriminants whose values affect the presence, constraints, or initialization of other components. Discriminants can be thought of as parameters of the type.
The term subcomponent is used in this Reference Manual in place of the term component to indicate either a component, or a component of another subcomponent. Where other subcomponents are excluded, the term component is used instead. Similarly, a part of an object or value is used to mean the whole object or value, or any set of its subcomponents. The terms component, subcomponent, and part are also applied to a type meaning the component, subcomponent, or part of objects and values of the type.
The set of possible values for an object of a given type can be subjected to a condition that is called a constraint (the case of a null constraint that specifies no restriction is also included)[; the rules for which values satisfy a given kind of constraint are given in 3.5 for
range_constraints, 3.6.1 for
index_constraints, and 3.7.1 for
discriminant_constraints]. The set of possible values for an object of an access type can also be subjected to a condition that excludes the null value (see 3.10).
A subtype of a given type is a combination of the type, a constraint on values of the type, and certain attributes specific to the subtype. The given type is called the type of the subtype. Similarly, the associated constraint is called the constraint of the subtype. The set of values of a subtype consists of the values of its type that satisfy its constraint and any exclusion of the null value. Such values belong to the subtype. The other values of the type are outside the subtype.
A subtype is called an unconstrained subtype if its type has unknown discriminants, or if its type allows range, index, or discriminant constraints, but the subtype does not impose such a constraint; otherwise, the subtype is called a constrained subtype (since it has no unconstrained characteristics).
ordinary fixed point
decimal fixed point
tagged (including interfaces)
nonlimited tagged record
limited tagged record
3.2.1 Type Declarations1
type_declaration declares a type and its first subtype.
A given type shall not have a subcomponent whose type is the given type itself.
defining_identifier of a
type_declaration denotes the first subtype of the type. The
known_discriminant_part, if any, defines the discriminants of the type (see 3.7, “Discriminants”). The remainder of the
type_declaration defines the remaining characteristics of (the view of) the type.
A type defined by a
type_declaration is a named type; such a type has one or more nameable subtypes. Certain other forms of declaration also include type definitions as part of the declaration for an object. The type defined by such a declaration is anonymous — it has no nameable subtypes. For explanatory purposes, this document sometimes refers to an anonymous type by a pseudo-name, written in italics, and uses such pseudo-names at places where the syntax normally requires an
identifier. For a named type whose first subtype is T, this document sometimes refers to the type of T as simply “the type T”.
object_declaration. An anonymous access type can be defined as part of numerous other constructs.
A named type that is declared by a
full_type_declaration, or an anonymous type that is defined by an
access_definition or as part of declaring an object of the type, is called a full type. The declaration of a full type also declares the full view of the type. The
access_definition that defines a full type is called a full type definition. [Types declared by other forms of
type_declaration are not separate types; they are partial or incomplete views of some full type.]
access_definitionseparately, as it may occur in renames, which do not declare objects.
The definition of a type implicitly declares certain predefined operators that operate on the type, according to what classes the type belongs, as specified in 4.5, “Operators and Expression Evaluation”.
if_statement— they don't need to be declared, but are still applicable to only certain classes of types.
The predefined types [(for example the types Boolean, Wide_Character, Integer, root_integer, and universal_integer)] are the types that are defined in [a predefined library package called] Standard[; this package also includes the [(implicit)] declarations of their predefined operators]. [The package Standard is described in A.1.]
The elaboration of a
full_type_declaration consists of the elaboration of the full type definition. Each elaboration of a full type definition creates a distinct type and its first subtype.
Examples of type definitions:
(White, Red, Yellow, Green, Blue, Brown, Black)
range 1 .. 72
array(1 .. 10) of Integer
Examples of type declarations:
type Color is (White, Red, Yellow, Green, Blue, Brown, Black);
type Column is range 1 .. 72;
type Table is array(1 .. 10) of Integer;
subtype_declarations (see 3.2.2). Although names do not directly denote types, a phrase like “the type Column” is sometimes used in this document to refer to the type of Column, where Column denotes the first subtype of the type. For an example of the definition of an anonymous type, see the declaration of the array Color_Table in 3.3.1; its type is anonymous — it has no nameable subtypes.
full_type_declarationnow includes task and protected type declarations.
discriminant_parts, because there is nothing to do, and it was complex to say that you only wanted to elaborate it once for a private or incomplete type. This is also consistent with the fact that subprogram specifications are not elaborated (neither in Ada 83 nor in Ada 95). Note, however, that an
access_definitionappearing in a
discriminant_partis elaborated at the
full_type_declaration(for a nonlimited type) or when an object with such a discriminant is created (for a limited type).
aspect_specificationcan be used in a
full_type_declaration. This is described in 13.1.1.
3.2.2 Subtype Declarations1
subtype_declaration declares a subtype of some previously declared type, as defined by a
attribute_reference; thus, S'Base can be used as a
subtype_name. However, existing users are used to the word "mark," so we're keeping it.
Name Resolution Rules8
subtype_mark shall resolve to denote a subtype. The type determined by a
subtype_mark is the type of the subtype denoted by the
subtype_marks denote subtypes — possibly an unconstrained (base) subtype, but never the type. When we use the term anonymous type we really mean a type with no nameable subtypes.
The elaboration of a
subtype_declaration consists of the elaboration of the
subtype_indication. The elaboration of a
subtype_indication creates a new subtype. If the
subtype_indication does not include a
constraint, the new subtype has the same (possibly null) constraint as that denoted by the
subtype_mark. The elaboration of a
subtype_indication that includes a
constraint proceeds as follows:
constraintis first elaborated. 11
- A check is then made that the
constraintis compatible with the subtype denoted by the
The condition imposed by a
constraint is the condition obtained after elaboration of the
constraint. The rules defining compatibility are given for each form of
constraint in the appropriate subclause. These rules are such that if a
constraint is compatible with a subtype, then the condition imposed by the
constraint cannot contradict any condition already imposed by the subtype on its values. The exception Constraint_Error is raised if any check of compatibility fails.
constraintis named after it — a
range_constraintimposes a range constraint, etc.
range_constraintcauses freezing of its type. Other
constraints do not.
scalar_constraintcan be applied to a subtype of an appropriate scalar type (see 3.5, 3.5.9, and J.3), even if the subtype is already constrained. On the other hand, a
composite_constraintcan be applied to a composite subtype (or an access-to-composite subtype) only if the composite subtype is unconstrained (see 3.6.1 and 3.7.1).
Examples of subtype declarations:
subtype Rainbow is Color range Red .. Blue; -- see 3.2.1 subtype Red_Blue is Rainbow; subtype Int is Integer; subtype Small_Int is Integer range -10 .. 10; subtype Up_To_K is Column range 1 .. K; -- see 3.2.1 subtype Square is Matrix(1 .. 10, 1 .. 10); -- see 3.6 subtype Male is Person(Sex => M); -- see 3.10.1 subtype Binop_Ref is not null Binop_Ptr; -- see 3.10
Incompatibilities With Ada 83
range_constraints cause freezing of their type. Hence, a type-related representation item for a scalar type has to precede any
range_constraints whose type is the scalar type.
Subtype_marks allow only subtype names now, since types are never directly named. There is no need for RM83-3.3.2(3), which says a
subtype_markcan denote both the type and the subtype; in Ada 95, you denote an unconstrained (base) subtype if you want, but never the type.
type_markis now called
subtype_mark, since it always denotes a subtype.
Extensions to Ada 95
null_exclusioncan be used in a
subtype_indication. This is described in 3.10.
aspect_specificationcan be used in a
subtype_declaration. This is described in 13.1.1.
3.2.3 Classification of Operations
An operation operates on a type T if it yields a value of type T, if it has an operand whose expected type (see 8.6) is T, or if it has an access parameter or access result type (see 6.1) designating T. A predefined operator, or other language-defined operation such as assignment or a membership test, that operates on a type, is called a predefined operation of the type. The primitive operations of a type are the predefined operations of the type, plus any user-defined primitive subprograms.
The primitive subprograms of a specific type are defined as follows:
- The predefined operators of the type (see 4.5);
- For a derived type, the inherited (see 3.4) user-defined subprograms;
- For an enumeration type, the enumeration literals (which are considered parameterless functions — see 3.5.1);
- For a specific type declared immediately within a
package_specification, any subprograms (in addition to the enumeration literals) that are explicitly declared immediately within the same
package_specificationand that operate on the type; 7.1/3
- For a specific type with an explicitly declared primitive "=" operator whose result type is Boolean, the corresponding "/=" operator (see 6.6);
- For a nonformal type, any subprograms not covered above [that are explicitly declared immediately within the same declarative region as the type] and that override (see 8.3) other implicitly declared primitive subprograms of the type.
A primitive subprogram whose designator is an
operator_symbol is called a primitive operator.
Incompatibilities With Ada 83
Extensions to Ada 83
Wording Changes from Ada 2005
3.2.4 Subtype Predicates1/5
The language-defined predicate aspects Static_Predicate and Dynamic_Predicate may be used to define properties of subtypes. A predicate specification is an
aspect_specification for one of the two predicate aspects. General rules for aspects and
aspect_specifications are found in Clause 13 (13.1 and 13.1.1 respectively). The predicate aspects are assertion aspects (see 11.4.2). [The predicate aspects are not inherited, but their effects are additive, as defined below.]
Name Resolution Rules2/3
The expected type for a predicate aspect
expression is any boolean type.
A predicate specification may be given on a
type_declaration or a
subtype_declaration, and applies to the declared subtype. In addition, predicate specifications apply to certain other subtypes:
- For a (first) subtype defined by a type declaration, any predicates of parent or progenitor subtypes apply.
- For a subtype created by a
subtype_indication, the predicate of the subtype denoted by the
This paragraph was deleted.
Predicate checks are defined to be enabled or disabled for a given subtype as follows:
- If a subtype is declared by a
subtype_declarationthat includes a predicate specification, then: 9/3
- if performing checks is required by the Static_Predicate assertion policy (see 11.4.2) and the declaration includes a Static_Predicate specification, then predicate checks are enabled for the subtype;
- if performing checks is required by the Dynamic_Predicate assertion policy (see 11.4.2) and the declaration includes a Dynamic_Predicate specification, then predicate checks are enabled for the subtype;
- otherwise, predicate checks are disabled for the subtype[, regardless of whether predicate checking is enabled for any other subtypes mentioned in the declaration];
- If a subtype is defined by a type declaration that does not include a predicate specification, then predicate checks are enabled for the subtype if and only if any predicate checks are enabled for parent or progenitor subtypes;
- If a subtype is created by a
subtype_indicationother than in one of the previous cases, then predicate checks are enabled for the subtype if and only if predicate checks are enabled for the subtype denoted by the
- Otherwise, predicate checks are disabled for the given subtype.
For a subtype with a directly-specified predicate aspect, the following additional language-defined aspect may be specified with an
aspect_specification (see 13.1.1):
- This aspect shall be specified by an
expression, which determines the action to be performed when a predicate check fails because a directly-specified predicate aspect of the subtype evaluates to False, as explained below.
Name Resolution Rules14.3/4
The expected type for the Predicate_Failure
expression is String.
expression of a Static_Predicate specification shall be predicate-static; that is, one of the following:
- a static expression;
- a membership test whose tested_
simple_expressionis the current instance, and whose
membership_choice_listmeets the requirements for a static membership test (see 4.9); 18/3
expressionis the current instance, and whose dependent_
expressions are static expressions; 19/3
- a call to a predefined equality or ordering operator, where one operand is the current instance, and the other is a static expression;
- a call to a predefined boolean operator and, or, xor, or not, where each operand is predicate-static;
- a short-circuit control form where both operands are predicate-static; or
- a parenthesized predicate-static
A predicate shall not be specified for an incomplete subtype.
If a predicate applies to a subtype, then that predicate shall not mention any other subtype to which the same predicate applies.
type Really_Ugly is private;
subtype Ugly is Really_Ugly;
type Really_Ugly is new Integer
with Static_Predicate => Really_Ugly not in Ugly; -- Illegal!
An index subtype,
discrete_range of an
slice, or a
discrete_subtype_definition of a
entry_index_specification shall not denote a subtype to which predicate specifications apply.
prefix of an
attribute_designator is First, Last, or Range shall not denote a scalar subtype to which predicate specifications apply.
discrete_subtype_definition of a
loop_parameter_specification shall not denote a nonstatic subtype to which predicate specifications apply or any subtype to which Dynamic_Predicate specifications apply.
discrete_choice of a
named_array_aggregate shall not denote a nonstatic subtype to which predicate specifications apply.
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.
If any of the above Legality Rules is violated in an instance of a generic unit, Program_Error is raised at the point of the violation.
To determine whether a value satisfies the predicates of a subtype S, the following tests are performed in the following order, until one of the tests fails, in which case the predicates are not satisfied and no further tests are performed, or all of the tests succeed, in which case the predicates are satisfied:
- the value is first tested to determine whether it satisfies any constraints or any null exclusion of S;
- if S is a first subtype, the value is tested to determine whether it satisfies the predicates of the parent and progenitor subtypes (if any) of S (in an arbitrary order), after a (view) conversion of the value to the corresponding parent or progenitor type;
- if S is defined by a
subtype_indication, the value is tested to determine whether it satisfies the predicates of the subtype denoted by the
- finally, if S is defined by a declaration to which one or more predicate specifications apply, the predicates are evaluated (in an arbitrary order) to test that all of them yield True for the given value.
If predicate checks are enabled for a given subtype, then:
[On a subtype conversion, a check is performed that the operand satisfies the predicates of the target subtype, except for certain view conversions (see 4.6). ] In addition, after normal completion and leaving of a subprogram, for each in out or out parameter that is passed by reference, a check is performed that the value of the parameter satisfies the predicates of the subtype of the actual. For an object created by an
object_declaration with no explicit initialization
expression, or by an uninitialized
allocator, if the types of any parts have specified Default_Value or Default_Component_Value aspects, or any subcomponents have
default_expressions, a check is performed that the value of the created object satisfies the predicates of the nominal subtype.
If any of the predicate checks fail, Assertion_Error is raised, unless the subtype whose directly-specified predicate aspect evaluated to False also has a directly-specified Predicate_Failure aspect. In that case, the specified Predicate_Failure
expression is evaluated; if the evaluation of the Predicate_Failure
expression propagates an exception occurrence, then this occurrence is propagated for the failure of the predicate check; otherwise, Assertion_Error is raised, with an associated message string defined by the value of the Predicate_Failure
expression. In the absence of such a Predicate_Failure aspect, an implementation-defined message string is associated with the Assertion_Error exception.
Paragraphs 32 and 33 were moved above
expressions are never evaluated during the evaluation of a membership test (see 4.5.2) or Valid attribute (see 13.9.2).
expressioncan be a
Examples of predicates applied to scalar types:
subtype Basic_Letter is Character -- See A.3.2 for "basic letter". with Static_Predicate => Basic_Letter in 'A'..'Z' | 'a'..'z' | 'Æ' | 'æ' | 'Ð' | 'ð' | 'Þ' | 'þ' | 'ß'; 41/4subtype Even_Integer is Integer with Dynamic_Predicate => Even_Integer mod 2 = 0, Predicate_Failure => "Even_Integer must be a multiple of 2";
Text_IO (see A.10.1) could have used predicates to describe some common exceptional conditions as follows:
with Ada.IO_Exceptions; package Ada.Text_IO is 44/4type File_Type is limited private; 45/4subtype Open_File_Type is File_Type with Dynamic_Predicate => Is_Open (Open_File_Type), Predicate_Failure => raise Status_Error with "File not open"; subtype Input_File_Type is Open_File_Type with Dynamic_Predicate => Mode (Input_File_Type) = In_File, Predicate_Failure => raise Mode_Error with "Cannot read file: " & Name (Input_File_Type); subtype Output_File_Type is Open_File_Type with Dynamic_Predicate => Mode (Output_File_Type) /= In_File, Predicate_Failure => raise Mode_Error with "Cannot write file: " & Name (Output_File_Type); 46/4... 47/4function Mode (File : in Open_File_Type) return File_Mode; function Name (File : in Open_File_Type) return String; function Form (File : in Open_File_Type) return String; 48/4... 49/4procedure Get (File : in Input_File_Type; Item : out Character); 50/4procedure Put (File : in Output_File_Type; Item : in Character); 51/4... 52/4-- Similarly for all of the other input and output subprograms.
Inconsistencies With Ada 2012
Extensions to Ada 2012
Wording Changes from Ada 2012
single_task_declaration, and generalized it.
assignment_statementwhen it is a view conversion. The rule change for this is found in 4.6, so the inconsistency is documented there.