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
Static Semantics
1A 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_statement
s 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_constraint
s, 3.6.1 for index_constraint
s, and 3.7.1 for discriminant_constraint
s]. 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).
elementary
scalar
discrete
enumeration
character
boolean
other enumeration
integer
signed integer
modular integer
real
floating point
fixed point
ordinary fixed point
decimal fixed point
access
access-to-object
access-to-subprogram
composite
untagged
array
string
other array
record
task
protected
tagged (including interfaces)
nonlimited tagged record
limited tagged
limited tagged record
synchronized tagged
tagged task
tagged protected
Wording Changes from Ada 83
Wording Changes from Ada 95
3.2.1 Type Declarations
1A type_declaration
declares a type and its first subtype.
Syntax
2type_declaration
::=
full_type_declaration
| incomplete_type_declaration
| private_type_declaration
| private_extension_declaration
3/3full_type_declaration
::=
type defining_identifier
[known_discriminant_part
] is type_definition
[aspect_specification
];
| task_type_declaration
| protected_type_declaration
4/2type_definition
::=
enumeration_type_definition
| integer_type_definition
| real_type_definition
| array_type_definition
| record_type_definition
| access_type_definition
| derived_type_definition
| interface_type_definition
Legality Rules
5A given type shall not have a subcomponent whose type is the given type itself.
Static Semantics
6The 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 type_definition
, task_definition
, protected_definition
, or 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_definition
separately, 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.]
Dynamic Semantics
11The 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
12Examples 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_declaration
s (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. Wording Changes from Ada 83
full_type_declaration
now includes task and protected type declarations.discriminant_part
s, 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_definition
appearing in a discriminant_part
is elaborated at the full_type_declaration
(for a nonlimited type) or when an object with such a discriminant is created (for a limited type). Wording Changes from Ada 95
Extensions to Ada 2005
aspect_specification
can be used in a full_type_declaration
. This is described in 13.1.1. 3.2.2 Subtype Declarations
1A subtype_declaration
declares a subtype of some previously declared type, as defined by a subtype_indication
.
Syntax
2/3subtype_declaration
::=
subtype defining_identifier
is subtype_indication
[aspect_specification
];
3/2subtype_indication
::=
[null_exclusion
] subtype_mark
[constraint
]
4subtype_mark
::=
subtype_name
subtype_mark
to subtype_name
. However, existing users are used to the word "mark," so we're keeping it. constraint
::=
scalar_constraint
| composite_constraint
6scalar_constraint
::=
range_constraint
| digits_constraint
| delta_constraint
7composite_constraint
::=
index_constraint
| discriminant_constraint
Name Resolution Rules
8A 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_mark
.
subtype_mark
s 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. Dynamic Semantics
9The 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:
- The
constraint
is first elaborated. 11 - A check is then made that the
constraint
is compatible with the subtype denoted by thesubtype_mark
.
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.
constraint
is named after it — a range_constraint
imposes a range constraint, etc. scalar_constraint
can 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_constraint
can 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
14Examples 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_constraint
s cause freezing of their type. Hence, a type-related representation item for a scalar type has to precede any range_constraint
s whose type is the scalar type. Wording Changes from Ada 83
Subtype_mark
s 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_mark
can denote both the type and the subtype; in Ada 95, you denote an unconstrained (base) subtype if you want, but never the type.Extensions to Ada 95
Extensions to Ada 2005
3.2.3 Classification of Operations
Static Semantics
1/2An 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 samepackage_specification
and 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 83
Wording Changes from Ada 95
Wording Changes from Ada 2005
3.2.4 Subtype Predicates
1/5The 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_specification
s 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 Rules
2/3The expected type for a predicate aspect expression
is any boolean type.
Static Semantics
3/3A 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 thesubtype_mark
applies.
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
type_declaration
orsubtype_declaration
that 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_indication
other 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 thesubtype_mark
; 14/3 - 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):
Predicate_Failure
- 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 Rules
14.3/4The expected type for the Predicate_Failure expression
is String.
Legality Rules
15/3The 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_expression
is the current instance, and whosemembership_choice_list
meets the requirements for a static membership test (see 4.9); 18/3 - a
case_expression
whose selecting_expression
is the current instance, and whose dependent_expression
s 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
expression
.
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;
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 index_constraint
or slice
, or a discrete_subtype_definition
of a constrained_array_definition
, entry_declaration
, or entry_index_specification
shall not denote a subtype to which predicate specifications apply.
The prefix
of an attribute_reference
whose attribute_designator
is First, Last, or Range shall not denote a scalar subtype to which predicate specifications apply.
The 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.
The 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.
Dynamic Semantics
29.1/4If 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;
- then:
- 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 thesubtype_mark
of thesubtype_indication
; 29.7/4 - 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_expression
s, 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
expression
s are never evaluated during the evaluation of a membership test (see 4.5.2) or Valid attribute (see 13.9.2).Examples
39/5Examples 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";
42/4Text_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.
Extensions to Ada 2005
Inconsistencies With Ada 2012
Extensions to Ada 2012
Wording Changes from Ada 2012
single_task_declaration
, and generalized it.assignment_statement
when it is a view conversion. The rule change for this is found in 4.6, so the inconsistency is documented there.