Version 1.1 of ai22s/ai22-0006-1.txt

Unformatted version of ai22s/ai22-0006-1.txt version 1.1
Other versions for file ai22s/ai22-0006-1.txt

!standard 4.3.3(20.3/5)          21-11-11 AI22-0006-1/01
!standard 4.3.3(20.4/5)
!standard 4.3.3(32/5)
!class binding interpretation 21-11-11
!status work item 21-11-11
!status received 21-11-11
!priority Medium
!difficulty Medium
!qualifier Omission
!subject Two-pass iteration for array aggregates
!summary
Counts must match for a "two pass" array aggregate.
!question
The array aggregates described in the three paragraphs starting at RM 4.3.3(20.2/5) are generated at run time via two passes. In the first pass, we generate a count that is an upper bound on the number of elements that the array aggregate is going to have. It is intended that this can be used in determining how much space to allocate for the aggregate object. In the second pass, we fill in the aggregate; the number of element values generated in the second pass is the actual length (that is, the number of elements) of the aggregate.
The use of "produced" in 4.3.3 (20.3/5) versus the use of "conditionally produced" in 4.3.3 (20.4/5) was intended to imply that filters only participate in the second pass. With this interpretation, it makes sense that the first count (which is generated without filters) might be larger than the second count (which is generated with filters).
However, allowing the case where the first count is greater than the second count introduces problems in some (obscure) build-in-place scenarios. Should these rules be revisited? (Yes.)
!recommendation
Evaluation of filters is required in the first pass and the two resulting element counts are checked for equality (as opposed to only checking that the first count is at least as large as the second). Strictly speaking, this is an incompatible change, but only with respect to an Ada2022 feature.
!wording
Replace 4.3.3(20.3/5 - 20.4/5): [Note the preceding lead-in paragraph is provided for readability, but it is not changed.]
For an array_aggregate that contains only array_component_associations that are iterated_component_associations with iterator_specifications, evaluation proceeds in two steps:
Each iterator_specification is elaborated (in an arbitrary order) and an iteration is performed solely to determine a maximum count for the number of values produced by the iteration; all of these counts are combined to determine the overall length of the array, and ultimately the limits on the bounds of the array (defined below);
A second iteration is performed for each of the iterator_specifications, in the order given in the aggregate, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2), the associated expression is evaluated, its value is converted to the component subtype of the array type, and used to define the value of the next component of the array starting at the low bound and proceeding sequentially toward the high bound. A check is made that the second iteration results in an array length no greater than the maximum determined by the first iteration; Constraint_Error is raised if this check fails.
with
For an array_aggregate that contains only array_component_associations that are iterated_component_associations with iterator_specifications, evaluation proceeds in two steps:
Each iterator_specification is elaborated (in an arbitrary order) and an iteration is performed solely to determine a count for the number of values conditionally produced by the iteration; all of these counts are combined to determine the overall length of the array, and ultimately the bounds of the array (defined below);
A second iteration is performed for each of the iterator_specifications, in the order given in the aggregate, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2), the associated expression is evaluated, its value is converted to the component subtype of the array type, and used to define the value of the next component of the array starting at the low bound and proceeding sequentially toward the high bound. A check is made that the second iteration results in the same number of elements as the first iteration; Constraint_Error is raised if this check fails. This check is performed before accessing the nonexistent (N+1)st element of the array object, where N is the count computed in the first iteration.
Modify 4.3.3(32/5) [Implementation Permissions]
When evaluating iterated_component_associations for an array_aggregate that contains only iterated_component_associations with iterator_specifications, the first step of evaluating an iterated_component_association can be omitted if the implementation can determine the number of values by some other means. {[Redundant: Such "other means" might include making use of an applicable index constraint or the Length function of a suitable container type.]}
!discussion
At least one compiler vendor has been confused about what is intended here, so some clarification is called for.
---
Build-in-place causes issues as one cannot use too much memory in such cases.
Consider the case where the first iteration yields a larger count, so we allocate more space for the aggregate than it requires. Now let's say that the array type is limited, the aggregate is returned as the result of a (BIP) function, the function call is used to initialize an allocator, and the access type in question has a user-defined storage pool.
type Vec is array (Some_Index_Type range <>) of Some_Limited_Type; function F return Vec is begin return <aggregate>; end F; type Ref is access Vec with Storage_Pool => ... ; Ptr : Ref := new Vec'(F);
Alternatively, omit the function and just use the aggregate to initialize the allocator.
There are two issues here:
1) Implementation complexity and overhead may be required to ensure that
the Max_Size_In_Storage_Elements implementation requirement of 13.11(21.5/3) is met when storage is allocated for the aggregate.
2) Suppose that later on we try to deallocate this allocated object via an
instance of Unchecked_Deallocation. In this case 13.11(21.7/3) requires that the Size_In_Storage_Elements parameter of the Free call has to equal that of the corresponding Allocate call. So an implementation would have to store this S_I_S_E value somewhere because it cannot be calculated from the bounds of the allocated array.
Compiler writers could deal with these issues, but it would be simpler (and cheaper in time and space) if they didn't have to.
---
Finally, it was unclear to at least some RM readers (thst is, me - Steve Baird) that the phrase "by some other means" in 4.3.3(32/5) includes the case where the aggregate has an applicable index constraint. In that case, it is intended that an implementation can omit the first pass and use the applicable index constraint instead to determine the value of the first count. It would be nice to see this point stated more explicitly.
!ACATS test
ACATS are needed for to check that the counts must match, and that Constraint_Error is raised if they do not.
!appendix

****************************************************************

Questions? Ask the ACAA Technical Agent