4.3 Aggregates
[
An
aggregate combines
component values into a composite value of an array type, record type,
or record extension.]
Term entry: aggregate —
construct used to define a value of a composite type by specifying the
values of the components of the type
Syntax
Name Resolution Rules
Ramification: {
AI05-0005-1}
There are additional rules for each kind of aggregate. These aggregate
rules are additive; a legal expression needs to satisfy all of the applicable
rules. That means the rule given here must be satisfied even when it
is syntactically possible to tell which specific kind of aggregate is
being used.
Legality Rules
Ramification: When the expected type
in some context is class-wide, an aggregate has to be explicitly qualified
by the specific type of value to be created, so that the expected type
for the aggregate itself is specific.
Discussion: We used to disallow
aggregates
of a type with unknown discriminants. However, that was unnecessarily
restrictive in the case of an extension aggregate, and irrelevant to
a record aggregate (since a type that is legal for a record aggregate
could not possibly have unknown discriminants) and to an array aggregate
(the only specific types that can have unknown discriminants are private
types, private extensions, and types derived from them).
Reason: {
AI12-0127-1}
We don't mention
delta_aggregates,
as those can get the specific type from the object represented by the
base_expression
(possibly at run time). We don't mention
array_aggregates,
as those cannot even be of a tagged type, so being class-wide is impossible.
Dynamic Semantics
For the evaluation of an
aggregate,
an anonymous object is created and values for the components or ancestor
part are obtained (as described in the subsequent subclause for each
kind of the
aggregate)
and assigned into the corresponding components or ancestor part of the
anonymous object.
Obtaining the values and the assignments
occur in an arbitrary order.
The value of the
aggregate
is the value of this object.
Discussion: The ancestor part is the
set of components inherited from the ancestor type. The syntactic category
ancestor_part
is the
expression
or
subtype_mark
that specifies how the ancestor part of the anonymous object should be
initialized.
Ramification: The assignment operations
do the necessary value adjustment, as described in
7.6.
Note that the value as a whole is not adjusted — just the subcomponents
(and ancestor part, if any).
7.6 also describes
when this anonymous object is finalized.
If the
ancestor_part
is a
subtype_mark
the Initialize procedure for the ancestor type is applied to the ancestor
part after default-initializing it, unless the procedure is abstract,
as described in
7.6. The Adjust procedure for
the ancestor type is not called in this case, since there is no assignment
to the ancestor part as a whole.
{
AI22-0007-1}
If an
aggregate
is of a tagged type, a check is made that its value belongs to the first
subtype of the type.
Constraint_Error is raised if
this check fails.
Any discriminant check is performed
before the initialization of any nondiscriminant component of the aggregate
object.
Ramification: This check ensures that
no values of a tagged type are ever outside the first subtype, as required
for inherited dispatching operations to work properly (see
3.4).
This check will always succeed if the first subtype is unconstrained.
This check is not extended to untagged types to preserve upward compatibility.
Reason: {
AI22-0007-1}
The order of checks and initializations is generally
unspecified. However, we need to do discriminant checks before initializing
any discriminant-dependent components, in order to avoid creating components
that the ultimate subtype does not have. Most such problems are prevented
by the rules about needed components for an aggregate
(see 4.3.1), but not those that result from
deriving from a constrained subtype.
Extensions to Ada 83
Wording Changes from Ada 83
We have adopted new wording for expressing the
rule that the type of an aggregate shall be determinable from the outside,
though using the fact that it is nonlimited record (extension) or array.
An
aggregate
now creates an anonymous object. This is necessary so that controlled
types will work (see
7.6).
Incompatibilities With Ada 95
{
AI95-00287-01}
In Ada 95, a limited type is not considered when
resolving an
aggregate.
Since Ada 2005 now allows limited
aggregates,
we can have incompatibilities. For example:
type Lim is limited
record
Comp: Integer;
end record;
type Not_Lim is
record
Comp: Integer;
end record;
procedure P(X: Lim);
procedure P(X: Not_Lim);
P((Comp => 123)); -- Illegal in Ada 2005, legal in Ada 95
The call to P is ambiguous in Ada 2005, while
it would not be ambiguous in Ada 95 as the
aggregate
could not have a limited type. Qualifying the
aggregate
will eliminate any ambiguity. This construction would be rather confusing
to a maintenance programmer, so it should be avoided, and thus we expect
it to be rare.
Extensions to Ada 95
Incompatibilities With Ada 2012
{
AI12-0005-1}
{
AI12-0127-1}
{
AI12-0212-1}
We now allow types with the Aggregate aspect specified
("container types"), as well as private types and extensions
descended from a record type or extension, to match all forms of
aggregate.
These types are only allowed for new types of
aggregate
(
container_aggregates
for the Aggregate aspect, and
delta_aggregates
for private types), but, consistent with other forms of
aggregate,
we do not look at the form of the
aggregate
to determine resolution. This can be incompatible in usually unlikely
cases, where overloading of a container or private type with a type that
was previously allowed in
aggregates
makes an existing call ambiguous. Unfortunately, Ada.Containers.Vectors
has a number of such overloadings for Insert, Append, Prepend, and "&",
so the problem may appear for any element type of a Vector that allows
aggregates. For instance, if My_Vector is an instance of Ada.Containers.Vectors
with an element type of Not_Lim as defined above, and V is an object
of My_Vector.Vector, then My_Vector.Append (V, (Comp => 123)); will
be illegal in Ada 2022 and legal in Ada 2012. This can easily be fixed
by qualifying the
aggregate
with the correct type.
Wording Changes from Ada 2022
{
AI22-0007-1}
Corrigendum: Clarified that discriminant
always occur before creating any non-discriminant components (in particular,
discriminant-dependent components). This is specifying unspecified behavior,
so it does not represent an inconsistency, but the possibility exists
that an unusual program where initialization (or lack thereof) of some
component has a side-effect that affects later execution would change
behavior.
{
AI22-0032-1}
Corrigendum: Corrected the omission of container_aggregates
from the list of aggregates
that cannot be class-wide. This could be considered an incompatibility,
but since no static or dynamic semantics are defined for such an aggregate,
it is unlikely that any implementation would usefully allow such a thing.
As such, it is highly unlikely to occur in any code.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe