3.6.1 Index Constraints and Discrete Ranges
An
index_constraint
determines the range of possible values for every index of an array subtype,
and thereby the corresponding array bounds.
Syntax
Name Resolution Rules
Legality Rules
Static Semantics
Dynamic Semantics
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.
Ramification: There is no need to define
compatibility with a constrained array subtype, because one is not allowed
to constrain it again.
{
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:
1.
determine the position number of the lower bound,
giving position number L;
2.
add one less than the length value to L,
giving the position number U; then
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.
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).
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.)
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.
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
Examples of array
declarations including an index constraint:
{
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
Example of array
declaration with a constrained array subtype:
My_Schedule : Schedule; -- all arrays of type Schedule have the same bounds
Example of record
type with a component that is an array:
type Var_Line(Length : Natural) is
record
Image : String(1 .. Length);
end record;
Null_Line : Var_Line(0); -- Null_Line.Image is a null array
Extensions to Ada 83
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
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
{
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).
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe