AI22-0155-1

!standard 3.6.2(10)                                    26-07-14  AI22-0155-1/04

!standard 4.9.1(2/5)

!standard 4.9.1(7/3)

!class Amendment 26-02-09

!status work item 26-02-09

!status received 25-11-02

!assigned author Tucker Taft

!submitter Tucker Taft

!priority Medium

!difficulty Medium

!subject Fixed lower bound for one-dimensional arrays

!summary

An aspect First may be specified on an array object or subtype which gives the lower bound for the one-dimensional array. The upper bound is calculated from the length.

!issue

When dealing with a (one-dimensional) unconstrained array subtype, the lower bound can be determined in various ways, depending on context. Most often the lower bound will be the lower bound of the index subtype, but in some cases, the lower bound might be some other value. A careful Ada programmer will always worry about this, and make computations relative to arr'First, but it is easy to miss this, and because the lower bound is usually that of the index subtypes, testing might not detect a case where the algorithm would fail if the lower bound is something else.

It could help if there were a way to specify that the lower bound of an object, particularly a formal parameter, will always have a specific value, no matter how the object is initialized.

Should a mechanism for specifying the lower bound be provided? (Yes)

!recommendation

We propose that the First aspect may be specified for a one-dimensional array object or subtype, and any value of that object/subtype will have that specified value as its lower bound, with the upper bound determined by the length of the array (and if the array is of zero length, the upper bound would always be 'First-1).

The First aspect may be specified on a formal parameter, on an object declaration, or on an array subtype definition. It may also be specified on a function or access-to-function, in which case it applies to the result subtype of the function.

!wording[a]

Add after 3.6.2(10):

The following subtype-specific aspect may be specified for a one-dimensional array subtype or object:

First

This aspect is specified by a static expression of the index subtype of the one-dimensional array. When specified, it means that an object of the subtype has a lower bound of the given value, and an upper bound that is calculated from the lower bound and the length of the array (see 3.6.1), notwithstanding what this document says elsewhere.

The First aspect may be specified on any of the following, provided the array subtype is otherwise unconstrained: an array type declaration, an array subtype declaration, a formal  type declaration of an array type, an array object declaration, a formal parameter specification of an array type, a formal object declaration of an array type, or a function, access-to-function, or formal function declaration with an array result type (in which case it applies to the function result subtype). When the First aspect applies to both a formal type and the corresponding actual subtype, the First aspects must statically match.

If the subtype denoted by the subtype_mark of a subtype_indication has a specified First aspect, the subtype defined by the subtype_indication has the same value for the First aspect. If the parent subtype of a derived_type_declaration has a specified First aspect, the first subtype of the derived type has the same value for the First aspect.  In both cases the value of the First aspect may be overridden with a new aspect_specification.

Modify 4.9.1(2/5):

A subtype statically matches another subtype of the same type if they have statically matching constraints, all predicate specifications that apply to them come from the same declarations, Nonblocking aspects have the same value, global aspects statically match,{ both or neither specify the First aspect (see 3.6.3), and if specified, the First aspects have the same value,} Object_Size (see 13.3) has been specified to have a nonconfirming value for either both or neither, and the nonconfirming values, if any, are the same, and, for access subtypes, either both or neither exclude null. Two anonymous access-to-object subtypes statically match if their designated subtypes statically match, and either both or neither exclude null, and either both or neither are access-to-constant. Two anonymous access-to-subprogram subtypes statically match if their designated profiles are subtype conformant, and either both or neither exclude null.

Add after 4.9.1(7/3):

!discussion

Worrying about bounds of one-dimension arrays takes more effort in Ada than in most languages. Clearly allowing lower bounds to be specified for an array gives added flexibility, but sometimes it comes at the cost of complexity and possible hidden errors. In particular for arrays where the lower bound has no special significance, it can be burdensome to always worry about whether the low bound of a given array matches the low bound of the index subtype, and for zero-length arrays, whether the high bound exactly equals the low bound minus one.

In part because of these issues, various language-defined functions that return strings are defined to always return a string with a lower bound of one (e.g. S'Image in 4.10). With the First aspect, we could define this directly in the function result subtype:

function S'Image(Arg : S'Base)
  return String with First => 1

 

Note that an aspect specification for First on a function (or access-to-function) is defined to apply to the result subtype.

Note that GNAT supports a syntax for declaring an array type or subtype with a fixed lower bound, so it would presumably be straightforward to adapt GNAT to use the First aspect specification approach. See:

https://gcc.gnu.org/onlinedocs/gnat_rm/Fixed-lower-bounds-for-array-types-and-subtypes.html

One important distinction with this proposal is the ability to specify First => 1 on a formal parameter or result subtype. It is quite convenient to be able to do this on any formal parameter or function result without having to declare a named subtype, as otherwise one could imagine having declarations for named subtypes like String_1 popping up everywhere.

We only propose to support single-dimensional arrays currently. If there were a real need for supporting multidimensional arrays, then probably a list of low bounds would make the most sense, such as:

type Multi is array (Positive range <>, Positive range <>) of Integer
  with First => (1, 1);

 

Having separate low bound specifications seems not very useful since you will almost always want to specify all of the low bounds if you specify any of them:

type Multi is array (Positive range <>, Positive range <>) of Integer
  with First(1) => 1, First(2) => 1;

 

More generally, the feature seems less interesting for multidimensional arrays as they don't provide slicing operations, and generally the low bounds are not being changed by any sort of normal operation. Essentially just using a precondition specifying the expected low bound(s) would seem to be adequate, since sliding is so rarely happening for multidimensional arrays. But if there is demand in the future, supporting the list-of-bounds notation would seem simplest.

!example

Specifying First can simplify the logic within a subprogram that takes an unconstrained array, such as a string, as input, and eliminates potential surprises from an algorithm that has never been tested with a low bound other than the low bound of the index subtype. For example:

procedure Manipulate_String
  (X : String with First => 1);
   -- Inside Manipulate_String, X'First will be one.

Note that specifying this on a formal parameter imposes no requirements on the actual parameter – no matter what bounds the actual parameter has, they will be renormalized for the formal to have a low bound of one, and a high bound matching the length, by "sliding" the array.

!ACATS test

A B-test could check that the First is specified with a static expression, and that the First aspect participates properly in statically-matching subtype checks. C-tests could verify that the low bound is always as specified, and the high bound is always low bound + length minus one in the presence of this aspect.

!appendix

This is related to a discussion in ARG GitHub issue #148.

[a]Need to make sure that conformance rules cover this, in analogy with not null.  Also need to make sure compatibility handles this properly.   Membership and qualification should be consistent, and require matching low bound.  May need wording in 4.6 to ensure sliding happens as desired.