Overview of Ada 2022
4.5 Container aggregates
Currently, it is quite
tedious to initialise a container, one has to create it as an empty container
and then add elements one at a time, as in:
X : My_Set := Empty_Set;
Include (X, 1);
Include (X, 2);
Include (X, 3);
Container aggregates; generalized array aggregates
(AI12-0212)
adds positional container aggregates (see RM
4.3.5).
These allow the above to be replaced by simply:
X : My_Set := [ 1, 2, 3 ];
Note that this uses square brackets not round brackets
(parentheses). This allows the use of [ ] to indicate an empty container,
analogous to "" indicating an empty string.
This is achieved using the new aspect
Aggregate
to indicate the appropriate function for returning an empty container
of the particular container type, and also the appropriate procedure
for adding an element to the particular container type.
For example:
type Set is tagged private
with -- Ada 2012 has these
Constant_Indexing => Constant_Reference,
Default_Iterator => Iterate,
Iterator_Element => Element_Type,
... -- but this is new
Aggregate => (Empty => Empty,
Add_Unnamed => Include),
...
Originally an
Empty_<Container>
constant was asked for in
AI12-0212,
but
Empty function for Container aggregates (AI12-0339)
tweaked this such that now an
Empty function
is given instead, so as to allow a
Capacity
parameter for those container types that have the concept of capacity
(e.g.
Vectors).
Add_Unnamed requires a
two parameter procedure for adding a single element. As the existing
Append procedures of vectors and lists required
a third,
Count, parameter,
Contracts for
container operations (AI12-0112)
added a procedure without the
Count parameter
(at the time called
Append_One) to the
Vectors
container, and
List containers need Append_One (AI12-0391)
did the same for the
Doubly_Link_Lists container.
Ambiguities associated with Vector Append and container aggregates
(AI12-0400)
then decided it was cleaner for the new procedures to be overloadings
of
Append, and to remove the default for
Count
(of := 1) from the original
Append procedures.
Iteration is also possible
within the container aggregate,
for example to create
a set whose elements all have double the value of the corresponding elements
of another set:
Doubles_Set : My_Set := [ for Item of X => Item * 2 ];
Note that this uses similar syntax to that introduced
by
Index parameters in array aggregates (AI12-0061)
(see
7.4).
And – prepare
yourself for a shock! – array aggregates are also allowed to use
square brackets
as an alternative to round brackets
(parentheses). This is to emphasise the similarity in characteristics
between containers and arrays, allow the use of [ ] for an empty array,
and allow the use of positional notation for a single element array.
Remember that
Two_Array : array (1 .. 2) of Positive := (1, 2);
is allowed, but not:
One_Array : array (1 .. 1) of Positive := (1); -- Illegal.
AI12-0212
also introduces two other kinds of container aggregates. These work similarly
to the positional container aggregates already described, so we won't
describe the details of defining these.
Named container aggregates allow the specification
of key choices along with element values, just like a named array aggregate.
For a named container aggregate, the choices can be of any type, so these
aggregates are especially useful for maps, as they can give the keys
and elements of a map at once. For instance, assuming an appropriate
map has been defined, one could write:
Retired : Expert_Map := ["Jeff" => True, "Randy" => False, "Tuck" => False];
Indexed container aggregates are similar to named
container aggregates except that they require the key choices to be of
a discrete type. In exchange for this requirement, indexed container
aggregates work similarly to an array aggregate, including a compile-time
check that all of the specified choices cover a single range with no
duplicates. Thus, using indexed container aggregates can help eliminate
errors. For instance:
Part_Time : Employee_Vector := [1 | 3 | 5..10 => False, 2 | 4 => True]; -- OK.
On_Vacation : Employee_Vector := [1 .. 4 | 8 .. 10 => False, 5 | 7 => True]; -- Illegal.
The second aggregate is illegal as employee #6 is
not specified.
One difference between container aggregates and array
aggregates is that no others choice is allowed in container aggregates.
An others choice only makes sense when the number of elements
in the resulting object is known at compile-time, and that is never the
case for containers.
Unfortunately introducing aggregates for containers
introduced an ambiguity – for the
Append,
Insert and
Prepend
operations of vectors, if the element type is a record then it is unclear
whether it is an element or another vector that is being added.
Ambiguities
associated with Vector Append and container aggregates (AI12-0400)
renames the operations for adding a vector to
Append_Vector,
Insert_Vector and
Prepend_Vector.
Note that this is a backward incompatibility; compiler vendors are strongly
encouraged to ease this incompatibility by adding these newly named routines
to their Ada 2012 implementations.
© 2021, 2022 Jeff Cousins