Annotated Ada Reference Manual (Ada 202y Draft 3)Legal Information
Contents   Index   References   Search   Previous   Next 

3.6.1 Index Constraints and Discrete Ranges

1
An index_constraint determines the range of possible values for every index of an array subtype, and thereby the corresponding array bounds. 

Syntax

2
index_constraint ::=  (discrete_range {, discrete_range})
3
discrete_range ::= discrete_subtype_indication | range

Name Resolution Rules

4
The type of a discrete_range is the type of the subtype defined by the subtype_indication, or the type of the range. For an index_constraint, each discrete_range shall resolve to be of the type of the corresponding index. 
4.a
Discussion: In Ada 95, index_constraints only appear in a subtype_indication; they no longer appear in constrained_array_definitions.

Legality Rules

5
An index_constraint shall appear only in a subtype_indication whose subtype_mark denotes either an unconstrained array subtype, or an unconstrained access subtype whose designated subtype is an unconstrained array subtype; in either case, the index_constraint shall provide a discrete_range for each index of the array type. 

Static Semantics

6
A discrete_range defines a range whose bounds are given by the range, or by the range of the subtype defined by the subtype_indication.

Dynamic Semantics

7
An index_constraint is compatible with an unconstrained array subtype if and only if the index range defined by each discrete_range is compatible (see 3.5) with the corresponding index subtype. If any of the discrete_ranges defines a null range, any array thus constrained is a null array, having no components. An array value satisfies an index_constraint if at each index position the array value and the index_constraint have the same index bounds. 
7.a
Ramification: There is no need to define compatibility with a constrained array subtype, because one is not allowed to constrain it again.
8
The elaboration of an index_constraint consists of the evaluation of the discrete_range(s), in an arbitrary order. The evaluation of a discrete_range consists of the elaboration of the subtype_indication or the evaluation of the range.
9/6
{AI22-0100-2} When the upper bound is calculated from the lower bound and another value representing the length of an array, the following steps are performed:
10/6
1.
determine the position number of the lower bound, giving position number L;
11/6
2.
add one less than the length value to L, giving the position number U; then
12/6
3.
the value of the index type whose position number is U is the value of the upper bound; if there is no value of the index type whose position number is U, Constraint_Error is raised.
12.a/6
Reason: We use position numbers as they are calculated as universal_integers, and thus have a theoretical unlimited range. For a static lower bound and length, the calculation should be exact. Using position numbers avoids problems that would be caused by using the index type for these calculations (no addition operation for enumeration types, and wrapping addition for modular types). 
12.b/6
Implementation Note: 4.4 allows using type root_integer to evaluate universal_integer expressions that have to be evaluated at runtime. So long as overflow is detected, that is sufficient for almost all standard discrete types (overflow corresponding to cases where the value is not representable as a value of the index type). (But be careful, the subtract of 1 has to be done to the length, not the lower bound, lest an incorrect overflow happen if the lower bound is the first value of the base type.) For the largest modular type (that with a modulus of System.Max_Binary_Modulus), however, some of the position numbers are not representable as root_integer. For that type, it is preferable to use unsigned math that detects overflow when runtime evaluation is required. (On typical machines, that means testing the carry flag rather than the overflow flag after math operations.) 
12.c/6
Ramification: As with S'Val, raising Constraint_Error is part of the semantics of the operation; it is not a check and cannot be suppressed. It seemed important to keep this operation consistent with S'Val. 
13
NOTE 1   The elaboration of a subtype_indication consisting of a subtype_mark followed by an index_constraint checks the compatibility of the index_constraint with the subtype_mark (see 3.2.2).
14
NOTE 2   Even if an array value does not satisfy the index constraint of an array subtype, Constraint_Error is not raised on conversion to the array subtype, so long as the length of each dimension of the array value and the array subtype match. See 4.6

Examples

15
Examples of array declarations including an index constraint: 
16/5
{AI12-0442-1} Board     : Matrix(1 .. 8,  1 .. 8);  -- see 3.6
Rectangle : Matrix(1 .. 20, 1 .. 30);
Inverse   : Matrix(1 .. N,  1 .. N);  -- N can be nonstatic
17/5
{AI125-0430-1} Filter    : Bit_Vector(0 .. 31);      -- see 3.6
18
Example of array declaration with a constrained array subtype: 
19
My_Schedule : Schedule;  -- all arrays of type Schedule have the same bounds
20
Example of record type with a component that is an array: 
21
type Var_Line(Length : Natural) is
   record
      Image : String(1 .. Length);
   end record;
22
Null_Line : Var_Line(0);  -- Null_Line.Image is a null array

Extensions to Ada 83

22.a
We allow the declaration of a variable with a nominally unconstrained array subtype, so long as it has an initialization expression to determine its bounds. 

Wording Changes from Ada 83

22.b
We have moved the syntax for index_constraint and discrete_range here since they are no longer used in constrained_array_definitions. We therefore also no longer have to describe the (special) semantics of index_constraints and discrete_ranges that appear in constrained_array_definitions.
22.c
The rules given in RM83-3.6.1(5,7-10), which define the bounds of an array object, are redundant with rules given elsewhere, and so are not repeated here. RM83-3.6.1(6), which requires that the (nominal) subtype of an array variable be constrained, no longer applies, so long as the variable is explicitly initialized. 

Wording Changes from Ada 2022

22.d/6
{AI22-0100-2} Added a description of how the upper bound is calculated from a lower bound and a length. Having this description clarifies what happens in various boundary conditions (which were not previously specified, although the ACATS has tested some of those cases since the 1980s).

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe