Version 1.12 of ai12s/ai12-0061-1.txt

Unformatted version of ai12s/ai12-0061-1.txt version 1.12
Other versions for file ai12s/ai12-0061-1.txt

!standard 4.3.3(5/2)          19-02-05 AI12-0061-1/07
!standard 4.3.3(6)
!standard 4.3.3(17/3)
!standard 4.3.3(20)
!standard 4.3.3(23.1/4)
!standard 4.3.3(32/3)
!standard 4.3.3(43)
!standard 3.1(6/3)
!standard 3.3(6)
!standard 3.3(18.1/3)
!standard 3.3.1(23/3)
!standard 5.5(6)
!standard 8.1(2.1/4)
!class Amendment 13-01-31
!status Amendment 1-2012 16-02-29
!status WG9 Approved 15-10-16
!status ARG Approved 10-0-0 15-06-27
!status work item 13-01-31
!status received 13-01-24
!priority Medium
!difficulty Easy
!subject Index parameters in array aggregates
!summary
Add parameterized_array_component_associations to array aggregates.
!problem
When the element type of an array is limited, it is not possible to create an aggregate that gives a different defined value to each component.
For instance, to call a function to initialize each element based on the index value, you would have used a for loop after the declaration of the array object. But this isn't possible if the type is limited.
We would like to be able to write something like
(for I in 1 .. Count => Function_Returning_Lim (I))
where Function_Returning_Lim returns a limited type, as this would provide a way to create an aggregate that would be difficult to create otherwise.
The Ada 9x team noted this problem in giving different discriminants to an array of tasks, see the example.
!proposal
Add a for-loop-like syntax to array aggregates. This syntax is for named array aggregates only (it cannot be used in positional aggregates).
!wording
Add to long semicolon-separated list of 3.1(6/3), after component_declararation (these are given in the order that they appear in the Standard):
an iterated_component_association;
Add after 3.3(6) (as a bulleted list item):
- the index parameter of an iterated_component_association;
Add after 3.3(18.1/3) (as a bulleted list item):
- the index parameter of an iterated_component_association;
Add ", iterated_component_association" in the comment-separated list of 3.3.1(23/3), immediately after ", iterator_specification".
Change 4.3.3(5/2) to:
array_component_association ::= discrete_choice_list => expression | discrete_choice_list => <> | iterated_component_association
iterated_component_association ::= for defining_identifier in discrete_choice_list => expression
Add after 4.3.3(6) (at the end of the syntax section):
The defining_identifier of an iterated_component_association declares an index parameter, an object of the corresponding index type.
Modify 4.3.3(17/3):
The discrete_choice_list of an array_component_association {(including an iterated_component_association)} is allowed to have a discrete_choice that is a nonstatic choice_expression ...
Append after 4.3.3(20) (at the end of the static semantics section)
The subtype (and nominal subtype) of an index parameter is the corresponding index subtype.
[We could define a more precise subtype, but the consensus at the Pittsburgh meeting was to keep this definition simple.]
Add after 4.3.3(23.1/4):
During an evaluation of the expression of an iterated_component_association, the value of the corresponding index parameter is that of the corresponding index of the corresponding array component.
AARM Ramification:
Taken together with the preceding rule that "The array component expressions of the aggregate are evaluated in an arbitrary order", this implies that an index parameter can take on its values in an arbitrary order. This is different than, for example, a loop parameter.
Add after 4.3.3(32/3):
Note:
An index parameter is a constant object (see 3.3).
[The note is intended to be similar to the note 5.5(10).]
Add after 4.3.3(43):
G : constant Matrix := (for I in 1 .. 4 => (for J in 1 .. 4 => (if I=J then 1.0 else 0.0))); -- Identity matrix
In 5.5(6), replace "whose subtype" with "whose subtype (and nominal subtype)". [Because the nominal subtype for a loop_parameter was never defined.]
Add after 8.1(4) (as a bulleted list item):
- an iterated_component_association;
Add to the list of 13.1.1(4.b/3): (after iterator specification)
iterated_component_association -- NO
!discussion
4.3.3(18) and 4.3.3(27) still work as the new syntax includes discrete_choice_list.
Note that this proposal allows iterating on a discrete_choice_list, so aggregates like:
(for I in 1 .. 3 | 5 .. 9 => I * I, 4 => 666)
are allowed. The rule about dynamic named choices still applies, so either the syntax is a regular for loop, or it can be expanded at compile time (as in the above example). Thus, the extra implementation burden of allowing a list should be minimal.
Note that the wording for AI12-0050 handles conformance for this new construct with no need for any further wording changes in this area. For example, we get the conformance we want for
subtype S is Integer range 1 .. 10; type Vec is array (S) of S;
procedure P (X : Vec := (for Idx in S => Idx)); procedure P (X : Vec := (for Idx in S => Idx)) is begin null; end;
!example
Using this feature to create an array of tasks that "know" their index within the array:
subtype Worker_Indexes is Natural range 1 .. 20;
task type Worker (Index : Worker_Indexes := 1) is ...
type Task_Array is array (Worker_Indexes) of Worker;
function Creator (Index : Worker_Indexes) return Worker is begin return Result : Worker (Index); end Creator;
Worker_Tasks : Task_Array := (for Index in Worker_Indexes => Creator (Index));
All of these tasks will be activated together, and they will know their position in the array (so that they can communicate directly with the neighbors) without needing an initialization entry call (which necessarily would serialize the starting of the tasks).
!corrigendum 3.1(6/3)
Replace the paragraph:
Each of the following is defined to be a declaration: any basic_declaration; an enumeration_literal_specification; a discriminant_specification; a component_declaration; a loop_parameter_specification; an iterator_specification; a parameter_specification; a subprogram_body; an extended_return_object_declaration; an entry_declaration; an entry_index_specification; a choice_parameter_specification; a generic_formal_parameter_declaration.
by:
Each of the following is defined to be a declaration: any basic_declaration; an enumeration_literal_specification; a discriminant_specification; a component_declaration; an iterated_component_association; a loop_parameter_specification; an iterator_specification; a parameter_specification; a subprogram_body; an extended_return_object_declaration; an entry_declaration; an entry_index_specification; a choice_parameter_specification; a generic_formal_parameter_declaration.
!corrigendum 3.3(6)
Insert after the paragraph:
the new paragraph:
!corrigendum 3.3(18.1/3)
Insert after the paragraph:
the new paragraph:
!corrigendum 3.3.1(23/3)
Replace the paragraph:
8 As indicated above, a stand-alone object is an object declared by an object_declaration. Similar definitions apply to "stand-alone constant" and "stand-alone variable." A subcomponent of an object is not a stand-alone object, nor is an object that is created by an allocator. An object declared by a loop_parameter_specification, iterator_specification, parameter_specification, entry_index_specification, choice_parameter_specification, extended_return_statement, or a formal_object_declaration of mode in out is not considered a stand-alone object.
by:
8 As indicated above, a stand-alone object is an object declared by an object_declaration. Similar definitions apply to "stand-alone constant" and "stand-alone variable." A subcomponent of an object is not a stand-alone object, nor is an object that is created by an allocator. An object declared by a loop_parameter_specification, iterator_specification, iterated_component_association, parameter_specification, entry_index_specification, choice_parameter_specification, extended_return_statement, or a formal_object_declaration of mode in out is not considered a stand-alone object.
!corrigendum 4.3.3(5/2)
Replace the paragraph:
array_component_association ::= discrete_choice_list => expression | discrete_choice_list => <>
by:
array_component_association ::= discrete_choice_list => expression | discrete_choice_list => <> | iterated_component_association
iterated_component_association ::= for defining_identifier in discrete_choice_list => expression
!corrigendum 4.3.3(6)
Insert after the paragraph:
An n-dimensional array_aggregate is one that is written as n levels of nested array_aggregates (or at the bottom level, equivalent string_literals). For the multidimensional case (n >= 2) the array_aggregates (or equivalent string_literals) at the n-1 lower levels are called subaggregates of the enclosing n-dimensional array_aggregate. The expressions of the bottom level subaggregates (or of the array_aggregate itself if one-dimensional) are called the array component expressions of the enclosing n-dimensional array_aggregate.
the new paragraph:
The defining_identifier of an iterated_component_association declares an index parameter, an object of the corresponding index type.
!corrigendum 4.3.3(17/3)
Replace the paragraph:
The discrete_choice_list of an array_component_association is allowed to have a discrete_choice that is a nonstatic choice_expression or that is a subtype_indication or range that defines a nonstatic or null range, only if it is the single discrete_choice of its discrete_choice_list, and there is only one array_component_association in the array_aggregate.
by:
The discrete_choice_list of an array_component_association (including an iterated_component_association) is allowed to have a discrete_choice that is a nonstatic choice_expression or that is a subtype_indication or range that defines a nonstatic or null range, only if it is the single discrete_choice of its discrete_choice_list, and there is only one array_component_association in the array_aggregate.
!corrigendum 4.3.3(20)
Insert after the paragraph:
A subaggregate that is a string_literal is equivalent to one that is a positional_array_aggregate of the same length, with each expression being the character_literal for the corresponding character of the string_literal.
the new paragraph:
The subtype (and nominal subtype) of an index parameter is the corresponding index subtype.
!corrigendum 4.3.3(23.1/4)
Insert after the paragraph:
Each expression in an array_component_association defines the value for the associated component(s). For an array_component_association with <>, the associated component(s) are initialized to the Default_Component_Value of the array type if this aspect has been specified for the array type; otherwise, they are initialized by default as for a stand-alone object of the component subtype (see 3.3.1).
the new paragraph:
During an evaluation of the expression of an iterated_component_association, the value of the corresponding index parameter is that of the corresponding index of the corresponding array component.
!corrigendum 4.3.3(32/3)
Insert after the paragraph:
NOTES
11 In an array_aggregate, positional notation may only be used with two or more expressions; a single expression in parentheses is interpreted as a parenthesized expression. A named_array_aggregate, such as (1 => X), may be used to specify an array with a single component.
the new paragraph:
12 An index parameter is a constant object (see 3.3).
!corrigendum 4.3.3(43)
Insert after the paragraph:
D : Bit_Vector(M .. N) := (M .. N => True); -- see 3.6 E : Bit_Vector(M .. N) := (others => True); F : String(1 .. 1) := (1 => 'F'); -- a one component aggregate: same as "F"
the new paragraph:
G : constant Matrix := (for I in 1 .. 4 => (for J in 1 .. 4 => (if I=J then 1.0 else 0.0))); -- Identity matrix
!corrigendum 5.5(6)
Replace the paragraph:
A loop_parameter_specification declares a loop parameter, which is an object whose subtype is that defined by the discrete_subtype_definition.
by:
A loop_parameter_specification declares a loop parameter, which is an object whose subtype (and nominal subtype) is that defined by the discrete_subtype_definition.
!corrigendum 8.1(2.1/4)
Insert after the paragraph:
the new paragraph:
!ASIS
** ASIS queries needed **
!ACATS test
ACATS B-Tests (to test 4.3.3(17-18) and the new rules) and C-Tests.
!appendix

!topic Index parameters in array aggregates
!reference 4.3.3
!from Adam Beneschan 13-01-24
!discussion

This is a proposal to allow "for <index_parameter> in
<discrete_choice_list>" in place of a <discrete_choice_list> in a
named array aggregate, where the expression on the right may refer to
the index parameter.  For instance:

   (for I in 1 .. 5 => I * I)

would be equivalent to the array aggregate

   (1 => 1, 2 => 4, 3 => 9, 4 => 16, 5 => 25)

This has been proposed in the past; Dan Eilers made a similar
suggestion before Ada 95 was adopted.  More recently, Phil Clayton
suggested the above syntax in July 2010; see the thread in
comp.lang.ada at

http://groups.google.com/group/comp.lang.ada/browse_thread/thread/334f9012742e58fc

(scroll down to Phil's first post in the thread).  Although the
proposal would be syntactic sugar in a case like the above, since you
can declare an array object and use a FOR loop to assign to each
element, it was pointed out in the comp.lang.ada thread that this
can't be done when the element type is limited.  In that case, a
syntax like

   (for I in 1 .. Count => Function_Returning_Lim (I))

where Function_Returning_Lim returns a limited type, might provide a
way to create an aggregate that would be difficult to create
otherwise. 

I've decided to try to come up with the RM changes myself, in the hope
that I might save someone else some work if this idea is pursued
(although I'm sure some editing would still be needed).

!wording

Change 4.3.3(5/2) to:

array_component_association ::=
   discrete_choice_list => expression
 | discrete_choice_list => <>
 | parameterized_array_component_association

Add after 4.3.3(5/2):

parameterized_array_component_association ::=
  for defining_identifier in discrete_choice_list => expression

A parameterized_array_component_association declares an index
parameter, which is an object whose type is the corresponding index
type.  If the discrete_choice_list is a single nonstatic
choice_expression or range, the constraint of the object's subtype is
the single value given by the choice_expression, or it is defined by
the range; otherwise, the bounds of the subtype's constraint are the
smallest and largest values covered by the discrete_choice_list.

Change 4.3.3(23) to:

2.  The array component expressions of the aggregate are evaluated in an
arbitrary order and their values are converted to the component
subtype of the array type; an array component expression is evaluated
once for each associated component.  For a
parameterized_array_component_association, before an array component
expression is evaluated for an associated component, the index of that
component is assigned to the index parameter.

Add to the end of 3.1(6/3):

In addition, a parameterized_array_component_association is a
declaration of its defining_identifier.

Add somewhere in 8.1(2-6):

. a parameterized_array_component_association;

Change the last sentence of 3.3.1(23/3) to:

An object declared by a loop_parameter_specification,
iterator_specification, parameter_specification,
entry_index_specification, choice_parameter_specification,
parameterized_array_component_association,
extended_return_statement, or a formal_object_declaration of mode in
out is not considered a stand-alone object.


NOTE on 4.3.3(17/3):

I don't think any change is required here; for the legality rules, a
discrete_choice_list in a parameterized_array_component_association
has the same effect as a discrete_choice_list in the other two types
of array_component_associations.  I don't think any wording change is
necessary, but for clarity it might be useful to change the first
phrase to

The discrete_choice_list of an array_component_association (including
the discrete_choice_list of a
parameterized_array_component_association) is allowed ...

Similarly for 4.3.3(27).


NOTE: In the aggregate 

   (1 .. 10 => Func_Call)

the component expressions are evaluated in an arbitrary order (by
4.3.3(23)), which means that if Func_Call has side effects and
returns a different value each time, you can't count on which result
of Func_Call will be assigned to which component.  I'm assuming that
the same would be true for 

   (for I in 1 .. 10 => Func_Call (I))

i.e. you can't tell which value will be passed to Func_Call first.
I'm assuming that no additional language is necessary, but a note in
the NOTES section could be helpful to avoid confusion, since people
could assume it would iterate like a for_loop_statement.

Note that this proposal allows anything that would be allowed in a
discrete_choice_list, e.g.

   Arr : Int_Array (1 .. 15) := 
            (for I in 1 | 3 | 6 | 10 .. 15 => I, 
             for J in others => -J);

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

Questions? Ask the ACAA Technical Agent