Ada Reference Manual (Ada 2022) — Legal Information

# 4.3.5 Container Aggregates

1/5
In a container_aggregate, values are specified for elements of a container; for a positional_container_aggregate, the elements are given sequentially; for a named_container_aggregate, the elements are specified by a sequence of key/value pairs, or using an iterator. The Aggregate aspect of the type of the aggregate determines how the elements are combined to form the container.
2/5
For a type other than an array type, the following type-related operational aspect may be specified:
3/5
Aggregate
This aspect is an aggregate of the form:
4/5
(Empty => name[,
Add_Named => procedure_name][,
Add_Unnamed => procedure_name][,
New_Indexed => function_name,
Assign_Indexed => procedure_name])
5/5
The type for which this aspect is specified is known as the container type of the Aggregate aspect. A procedure_name shall be specified for at least one of Add_Named, Add_Unnamed, or Assign_Indexed. If Add_Named is specified, neither Add_Unnamed nor Assign_Indexed shall be specified. Either both or neither of New_Indexed and Assign_Indexed shall be specified.

#### Name Resolution Rules

6/5
The name specified for Empty for an Aggregate aspect shall denote a constant of the container type, or denote exactly one function with a result type of the container type that has no parameters, or that has one in parameter of a signed integer type.
7/5
The procedure_name specified for Add_Unnamed for an Aggregate aspect shall denote exactly one procedure that has two parameters, the first an in out parameter of the container type, and the second an in parameter of some nonlimited type, called the element type of the container type.
8/5
The function_name specified for New_Indexed for an Aggregate aspect shall denote exactly one function with a result type of the container type, and two parameters of the same discrete type, with that type being the key type of the container type.
9/5
The procedure_name specified for Add_Named or Assign_Indexed for an Aggregate aspect shall denote exactly one procedure that has three parameters, the first an in out parameter of the container type, the second an in parameter of a nonlimited type (the key type of the container type), and the third, an in parameter of a nonlimited type that is called the element type of the container type.

#### Legality Rules

10/5
If the container type of an Aggregate aspect is a private type, the full type of the container type shall not be an array type. If the container type is limited, the name specified for Empty shall denote a function rather than a constant object.
11/5
For an Aggregate aspect, the key type of Assign_Indexed shall be the same type as that of the parameters of New_Indexed. Additionally, if both Add_Unnamed and Assign_Indexed are specified, the final parameters shall be of the same type — the element type of the container type.

#### Static Semantics

12/5
The Aggregate aspect is nonoverridable (see 13.1.1).

#### Syntax

13/5
container_aggregate ::=
null_container_aggregate
| positional_container_aggregate
| named_container_aggregate
14/5
null_container_aggregate ::= '[' ']'
15/5
positional_container_aggregate ::= '[' expression{, expression} ']'
16/5
named_container_aggregate ::= '[' container_element_association_list ']'
17/5
container_element_association_list ::=
container_element_association {, container_element_association}
18/5
container_element_association ::=
key_choice_list => expression
| key_choice_list => <>
| iterated_element_association
19/5
key_choice_list ::= key_choice {'|' key_choice}
20/5
key_choice ::= key_expression | discrete_range
21/5
iterated_element_association ::=
for loop_parameter_specification[ use key_expression] => expression
| for iterator_specification[ use key_expression] => expression

#### Name Resolution Rules

22/5
The expected type for a container_aggregate shall be a single type for which the Aggregate aspect has been specified. The expected type for each expression of a container_aggregate is the element type of the expected type.
23/5
The expected type for a key_expression, or a discrete_range of a key_choice, is the key type of the expected type of the aggregate.

#### Legality Rules

24/5
The expected type for a positional_container_aggregate shall have an Aggregate aspect that includes a specification for an Add_Unnamed procedure or an Assign_Indexed procedure. The expected type for a named_container_aggregate that contains one or more iterated_element_associations with a key_expression shall have an Aggregate aspect that includes a specification for the Add_Named procedure. The expected type for a named_container_aggregate that contains one or more key_choice_lists shall have an Aggregate aspect that includes a specification for the Add_Named or Assign_Indexed procedure. A null_container_aggregate can be of any type with an Aggregate aspect.
25/5
A non-null container aggregate is called an indexed aggregate if the expected type T of the aggregate specifies an Assign_Indexed procedure in its Aggregate aspect, and either there is no Add_Unnamed procedure specified for the type, or the aggregate is a named_container_aggregate with a container_element_association that contains a key_choice_list or a loop_parameter_specification. The key type of an indexed aggregate is also called the index type of the aggregate.
26/5
A container_element_association with a <> rather than an expression, or with a key_choice that is a discrete_range, is permitted only in an indexed aggregate.
27/5
For an iterated_element_association without a key_expression, if the aggregate is an indexed aggregate or the expected type of the aggregate specifies an Add_Named procedure in its Aggregate aspect, then the type of the loop parameter of the iterated_element_association shall be the same as the key type of the aggregate.
28/5
For a named_container_aggregate that is an indexed aggregate, all container_element_associations shall contain either a key_choice_list, or a loop_parameter_specification without a key_expression or iterator_filter. Furthermore, for such an aggregate, either:
29/5
all key_choices shall be static expressions or static ranges, and every loop_parameter_specification shall have a discrete_subtype_definition that defines a non-null static range, and the set of values of the index type covered by the key_choices and the discrete_subtype_definitions shall form a contiguous range of values with no duplications; or
30/5
there shall be exactly one container_element_association, and if it has a key_choice_list, the list shall have exactly one key_choice.

#### Dynamic Semantics

31/5
The evaluation of a container_aggregate starts by creating an anonymous object A of the expected type T, initialized as follows:
32/5
if the aggregate is an indexed aggregate, from the result of a call on the New_Indexed function; the actual parameters in this call represent the lower and upper bound of the aggregate, and are determined as follows:
33/5
if the aggregate is a positional_container_aggregate, the lower bound is the low bound of the subtype of the key parameter of the Add_Indexed procedure, and the upper bound has a position number that is the sum of the position number of the lower bound and one less than the number of expressions in the aggregate;
34/5
if the aggregate is a named_container_aggregate, the lower bound is the lowest value covered by a key_choice_list or is the low bound of a range defined by a discrete_subtype_definition of a loop_parameter_specification; the upper bound is the highest value covered by a key_choice_list or is the high bound of a range defined by a discrete_subtype_definition of a loop_parameter_specification.
35/5
if the aggregate is not an indexed aggregate, by assignment from the Empty constant, or from a call on the Empty function specified in the Aggregate aspect. In the case of an Empty function with a formal parameter, the actual parameter has the following value:
36/5
for a null_container_aggregate, the value zero;
37/5
for a positional_container_aggregate, the number of expressions;
38/5
for a named_container_aggregate without an iterated_element_association, the number of key_expressions;
39/5
for a named_container_aggregate where every iterated_element_association contains a loop_parameter_specification, the total number of elements specified by all of the container_element_associations;
40/5
otherwise, to an implementation-defined value.
41/5
The evaluation then proceeds as follows:
42/5
for a null_container_aggregate, the anonymous object A is the result;
43/5
for a positional_container_aggregate of a type with a specified Add_Unnamed procedure, each expression is evaluated in an arbitrary order, and the Add_Unnamed procedure is invoked in sequence with the anonymous object A as the first parameter and the result of evaluating each expression as the second parameter, in the order of the expressions;
44/5
for a positional_container_aggregate that is an indexed aggregate, each expression is evaluated in an arbitrary order, and the Assign_Indexed procedure is invoked in sequence with the anonymous object A as the first parameter, the key value as the second parameter, computed by starting with the low bound of the subtype of the key formal parameter of the Assign_Indexed procedure and taking the successor of this value for each successive expression, and the result of evaluating each expression as the third parameter;
45/5
for a named_container_aggregate for a type with an Add_Named procedure in its Aggregate aspect, the container_element_associations are evaluated in an arbitrary order:
46/5
for a container_element_association with a key_choice_list, for each key_choice of the list in an arbitrary order, the key_choice is evaluated as is the expression of the container_element_association (in an arbitrary order), and the Add_Named procedure is invoked once for each value covered by the key_choice, with the anonymous object A as the first parameter, the value from the key_choice as the second parameter, and the result of evaluating the expression as the third parameter;
47/5
for a container_element_association with an iterated_element_association, first the iterated_element_association is elaborated, then an iteration is performed, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2) the Add_Named procedure is invoked with the anonymous object A as the first parameter, the result of evaluating the expression as the third parameter, and:
48/5
if there is a key_expression, the result of evaluating the key_expression as the second parameter;
49/5
otherwise, with the loop parameter as the second parameter;
50/5
for a named_container_aggregate that is an indexed aggregate, the evaluation proceeds as above for the case of Add_Named, but with the Assign_Indexed procedure being invoked instead of Add_Named; in the case of a container_element_association with a <> rather than an expression, the corresponding call on Assign_Indexed is not performed, leaving the component as it was upon return from the New_Indexed function;
51/5
for any other named_container_aggregate, the container_element_associations (which are necessarily iterated_element_associations) are evaluated in the order given; each such evaluation comprises two steps:
52/5
1.
the iterated_element_association is elaborated;
53/5
2.
an iteration is performed, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2) the Add_Unnamed procedure is invoked, with the anonymous object A as the first parameter and the result of evaluating the expression as the second parameter.

#### Examples

54/5
Examples of specifying the Aggregate aspect for a Set_Type, a Map_Type, and a Vector_Type:
55/5
-- Set_Type is a set-like container type.
type Set_Type is private
with Aggregate => (Empty => Empty_Set,
Add_Unnamed => Include);
function Empty_Set return Set_Type;
56/5
subtype Small_Int is Integer range -1000..1000;
57/5
procedure Include (S : in out Set_Type; N : in Small_Int);
58/5
-- Map_Type is a map-like container type.
type Map_Type is private
with Aggregate => (Empty => Empty_Map,
Add_Named => Add_To_Map);
59/5
procedure Add_To_Map (M : in out Map_Type;
Key : in Integer;
Value : in String);
60/5
Empty_Map : constant Map_Type;
61/5
-- Vector_Type is an extensible array-like container type.
type Vector_Type is private
with Aggregate => (Empty => Empty_Vector,
Add_Unnamed => Append_One,
New_Indexed => New_Vector,
Assign_Indexed => Assign_Element);
62/5
function Empty_Vector (Capacity : Integer := 0) return Vector_Type;
63/5
procedure Append_One (V : in out Vector_Type; New_Item : in String);
64/5
procedure Assign_Element (V : in out Vector_Type;
Index : in Positive;
Item : in String);
65/5
function New_Vector (First, Last : Positive) return Vector_Type
with Pre => First = Positive'First;
-- Vectors are always indexed starting at the
-- lower bound of their index subtype.
66/5
-- Private part not shown.
67/5
Examples of container aggregates for Set_Type, Map_Type, and Vector_Type:
68/5
-- Example aggregates using Set_Type.
S : Set_Type;
69/5
-- Assign the empty set to S:
S := [];
70/5
-- Is equivalent to:
S := Empty_Set;
71/5
-- A positional set aggregate:
S := [1, 2];
72/5
-- Is equivalent to:
S := Empty_Set;
Include (S, 1);
Include (S, 2);
73/5
-- A set aggregate with an iterated_element_association:
S := [for Item in 1 .. 5 => Item * 2];
74/5
-- Is equivalent to:
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item * 2);
end loop;
75/5
-- A set aggregate consisting of two iterated_element_association s:
S := [for Item in 1 .. 5 => Item,
for Item in 1 .. 5 => -Item];
76/5
-- Is equivalent (assuming set semantics) to:
S := Empty_Set;
for Item in 1 .. 5 loop
Include (S, Item);
end loop;
for Item in -5 .. -1 loop
Include (S, Item);
end loop;
77/5
-- Example aggregates using Map_Type.
M : Map_Type;
78/5
-- A simple named map aggregate:
M := [12 => "house", 14 => "beige"];
79/5
-- Is equivalent to:
M := Empty_Map;
Add_To_Map (M, 12, "house");
Add_To_Map (M, 14, "beige");
80/5
-- Define a table of pairs:
type Pair is record
Key : Integer;
Value : access constant String;
end record;
81/5
Table : constant array(Positive range <>) of Pair :=
[(Key => 33, Value => new String'("a nice string")),
(Key => 44, Value => new String'("an even better string"))];
82/5
-- A map aggregate using an iterated_element_association
-- and a key_expression, built from from a table of key/value pairs:
M := [for P of Table use P.Key => P.Value.all];
83/5
-- Is equivalent to:
M := Empty_Map;
for P of Table loop
Add_To_Map (M, P.Key, P.Value.all);
end loop;
84/5
-- Create an image table for an array of integers:
Keys : constant array(Positive range <>) of Integer := [2, 3, 5, 7, 11];
85/5
-- A map aggregate where the values produced by the
-- iterated_element_association are of the same type as the key
-- (hence a separate key_expression is unnecessary):
M := [for Key of Keys => Integer'Image (Key)];
86/5
-- Is equivalent to:
M := Empty_Map;
for Key of Keys loop
Add_To_Map (M, Key, Integer'Image (Key));
end loop;
87/5
-- Example aggregates using Vector_Type.
V : Vector_Type;
88/5
-- A positional vector aggregate:
V := ["abc", "def"];
89/5
-- Is equivalent to:
V := Empty_Vector (2);
Append_One (V, "abc");
Append_One (V, "def");
90/5
-- An indexed vector aggregate:
V := [1 => "this", 2 => "is", 3 => "a", 4 => "test"];
91/5
-- Is equivalent to:
V := New_Vector (1, 4);
Assign_Element (V, 1, "this");
Assign_Element (V, 2, "is");
Assign_Element (V, 3, "a");
Assign_Element (V, 4, "test");

Ada 2005 and 2012 Editions sponsored in part by Ada-Europe