4.3 Aggregates
This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue
[ 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
2/5aggregate
::=
record_aggregate
| extension_aggregate
| array_aggregate
| delta_aggregate
| container_aggregate
Name Resolution Rules
3/5The expected type for an aggregate
shall be a single array type, a single type with the Aggregate aspect specified, or a single descendant of a record type or of a record extension.
See 8.6, “The Context of Overload Resolution” for the meaning of “shall be a single ... type”.
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.
Generally, we don't want to look in aggregate
s to resolve them. For instance, Ada 95 allowed array types to match extension_aggregate
s, even though those have to be record types. Thus, we allow any record type with any visible (nondiscriminant) components to match an aggregate
, even though only delta_aggregate
s allow private types or private extensions. Similarly, we allow any container type to match an aggregate
, even though only container_aggregate
s allow container types.
Legality Rules
4/5A record_aggregate
or extension_aggregate
shall not be of a class-wide type.
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.
We used to disallow aggregate
s 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).
We don't mention delta_aggregate
s, as those can get the specific type from the object represented by the base_expression
(possibly at run time). We don't mention array_aggregate
s, as those cannot even be of a tagged type, so being class-wide is impossible.
Dynamic Semantics
5For 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.
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.
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.
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.
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.
Extensions to Ada 83
We now allow extension_aggregate
s.
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.
Incompatibilities With Ada 95
type Lim is limited
record
Comp: Integer;
end record;
6.g/2
type Not_Lim is
record
Comp: Integer;
end record;
6.h/2
procedure P(X: Lim);
procedure P(X: Not_Lim);
6.i/2
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
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_aggregate
s for the Aggregate aspect, and delta_aggregate
s 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 aggregate
s 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.
4.3.1 Record Aggregates
1[In a record_aggregate
, a value is specified for each component of the record or record extension value, using either a named or a positional association.]
Syntax
2record_aggregate
::=
(record_component_association_list
)
3
record_component_association_list
::=
record_component_association
{, record_component_association
}
| null record
4/2
record_component_association
::=
[component_choice_list
=>] expression
| component_choice_list
=> <>
5/5
component_choice_list
::=
component_selector_name
{'|' component_selector_name
}
| others
6
A record_component_association
is a named component association if it has a component_choice_list
; otherwise, it is a positional component association. Any positional component associations shall precede any named component associations. If there is a named association with a component_choice_list
of others, it shall come last.
These rules were implied by the BNF in an early version of the RM9X, but it made the grammar harder to read, and was inconsistent with how we handle discriminant constraints. Note that for array aggregates we still express some of the rules in the grammar, but array aggregates are significantly different because an array aggregate is either all positional (with a possible others at the end), or all named.
In the record_component_association_list
for a record_aggregate
, if there is only one association, it shall be a named association.
Otherwise, the construct would be interpreted as a parenthesized expression. This is considered a syntax rule, since it is relevant to overload resolution. We choose not to express it with BNF so we can share the definition of record_component_association_list
in both record_aggregate
and extension_aggregate
.
The record_component_association_list
of an extension_aggregate
does not have such a restriction.
Name Resolution Rules
8/2The expected type for a record_aggregate
shall be a single record type or record extension.
This rule is used to resolve whether an aggregate
is an array_aggregate
or a record_aggregate
. The presence of a with is used to resolve between a record_aggregate
and an extension_aggregate
.
For the record_component_association_list
of a record_aggregate
, all components of the composite value defined by the aggregate are needed[; for the association list of an extension_aggregate
, only those components not determined by the ancestor expression or subtype are needed (see 4.3.2).] Each component_selector_name
in a record_component_association
of a record_aggregate
or extension_aggregate
shall denote a needed component [(including possibly a discriminant)]. Each component_selector_name
in a record_component_association
of a record_delta_aggregate
(see 4.3.4) shall denote a nondiscriminant component of the type of the aggregate
.
For the association list of a record_aggregate
, “needed components” includes every component of the composite value, but does not include those in unchosen variant
s (see AI83-309). If there are variant
s, then the value specified for the discriminant that governs them determines which variant
is chosen, and hence which components are needed.
If an extension defines a new known_discriminant_part
, then all of its discriminants are needed in the component association list of an extension aggregate for that type, even if the discriminants have the same names and types as discriminants of the type of the ancestor expression. This is necessary to ensure that the positions in the record_component_association_list
are well defined, and that discriminants that govern variant_part
s can be given by static expressions.
We don't define “needed” for record_delta_aggregate
s so that there is no completeness requirement. But that means that we need to ensure that the rules using “needed” doesn't appear to apply to record_delta_aggregate
s, and we also need Legality Rules to prevent giving the same component twice and giving components from two different variants.
Term entry: needed component — component of a record type or record extension that is required to have its value specified within a given aggregate
The expected type for the expression
of a record_component_association
is the type of the associated component(s); the associated component(s) are as follows:
- For a positional association, the component [(including possibly a discriminant)] in the corresponding relative position (in the declarative region of the type), counting only the needed components;
This means that for an association list of an extension_aggregate
, only noninherited components are counted to determine the position.
For a derived type (including type extensions), the order of declaration is defined in 3.4, “Derived Types and Classes”. In particular, all discriminants come first, regardless of whether they are defined for the parent type or are newly added to the derived type.
- For a named association with one or more component_
selector_name
s, the named component(s); 13 - For a named association with the reserved word others, all needed components that are not associated with some previous association.
Legality Rules
14If the type of a record_aggregate
is a record extension, then it shall be a descendant of a record type, through one or more record extensions (and no private extensions).
A record_component_association_list
shall be null record only if the list occurs in a record_aggregate
or extension_aggregate
, and there are no components needed for that list.
For example, "(null record)" is a record_aggregate
for a null record type. Similarly, "(T'(A) with null record)" is an extension_aggregate
for a type defined as a null record extension of T.
If no components are needed and null record is not used, the record_component_association
must necessarily be others => <>, as that is the only record_component_association
that does not require an associated component.
For a record_aggregate
or extension_aggregate
, each record_component_association
other than an others choice with a <> shall have at least one associated component, and each needed component shall be associated with exactly one record_component_association
. For a record_delta_aggregate
, each component_selector_name
of each component_choice_list
shall denote a distinct nondiscriminant component of the type of the aggregate.
These rules apply to an association with an others choice with an expression. An others choice with a <> can match zero components or several components with different types.
Without these rules, there would be no way to know what was the expected type for the expression
of the association. Note that some of the rules do not apply to <> associations, as we do not need to resolve anything. We allow others => <> to match no components as this is similar to array aggregates. That means that (others => <>) always represents a default-initialized record or array value.
The rule that requires at least one associated component for each record_component_association
implies that there can be no extra associations for components that don't exist in the composite value, or that are already determined by the ancestor expression or subtype of an extension_aggregate
.
The second part of the first sentence ensures that no needed components are left out, nor specified twice.
If a record_component_association
with an expression
has two or more associated components, all of them shall be of the same type, or all of them shall be of anonymous access types whose subtypes statically match. In addition, Legality Rules are enforced separately for each associated component.
AI83-00244 also requires that the expression
shall be legal for each associated component. Ada 95 omitted this wording, as it was thought that all cases of difference had been eliminated. That probably was true, but Ada 2005 reintroduced cases where the types match but the legality differs. For example:
type Rec (D : access Integer) is record
F : access Integer;
end record;
16.h/5
begin
declare
X : aliased Integer;
R : Rec := (D | F => X'Access); -- Legal for D, illegal for F
There are additional ways for this to happen; because of cases like the above we require that the Legality Rules are checked individually for each associated component.
For a record_aggregate
or extension_aggregate
, if a variant_part
P is nested within a variant
V that is not selected by the discriminant value governing the variant_part
enclosing V, then there is no restriction on the discriminant governing P. Otherwise, the value of the discriminant that governs P shall be given by a static expression, or by a nonstatic expression having a constrained static nominal subtype. In this latter case of a nonstatic expression, there shall be exactly one discrete_choice_list
of P that covers each value that belongs to the nominal subtype and satisfies the predicates of the subtype, and there shall be at least one such value.
This expression might either be given within the aggregate itself, or in a constraint on the parent subtype in a derived_type_definition
for some ancestor of the type of the aggregate.
A record_component_association
for a discriminant without a default_expression
shall have an expression
rather than <>.
A discriminant must always have a defined value, but <> means uninitialized for a discrete type unless the component has a default value.
A record_component_association
of the record_component_association_list
of a record_delta_aggregate
shall not:
- use the box compound delimiter <> rather than an
expression
; 17.4/5 - have an
expression
of a limited type; 17.5/5 - omit the
component_choice_list
; or
A record_delta_aggregate
cannot use positional notation; all choices shall be named choices.
- have a
component_choice_list
that is an others choice.
For a record_delta_aggregate
, no two component_selector_name
s shall denote components declared within different variant
s of the same variant_part
.
Dynamic Semantics
18The evaluation of a record_aggregate
consists of the evaluation of the record_component_association_list
.
For the evaluation of a record_component_association_list
, any per-object constraints (see 3.8) for components specified in the association list are elaborated and any expression
s are evaluated and converted to the subtype of the associated component. Any constraint elaborations and expression
evaluations (and conversions) occur in an arbitrary order, except that the expression
for a discriminant is evaluated (and converted) prior to the elaboration of any per-object constraint that depends on it, which in turn occurs prior to the evaluation and conversion of the expression
for the component with the per-object constraint. If the value of a discriminant that governs a selected variant_part
is given by a nonstatic expression
, and the evaluation of that expression
yields a value that does not belong to the nominal subtype of the expression
, then Constraint_Error is raised.
The conversion in the first rule might raise Constraint_Error.
This check in the first rule presumably happened as part of the dependent compatibility check in Ada 83.
The test on the value of the discriminant can only fail if the value is outside the base range of its type, does not satisfy the (static) predicates of the subtype (possible when the predicate is disabled), or is an invalid representation. This is a rule similar to that used for case statements. As with case statements, this is not a “check”; it cannot be Suppressed.
For a record_component_association
with an expression
, the expression
defines the value for the associated component(s). For a record_component_association
with <>, if the component_declaration
has a default_expression
, that default_expression
defines the value for the associated component(s); otherwise, the associated component(s) are initialized by default as for a stand-alone object of the component subtype (see 3.3.1).
The expression
of a record_component_association
is evaluated (and converted) once for each associated component.
We don't need similar language for <>, as we're considering the value of <> for each individual component. Each component has its own default expression or its own default initialization (they can be different for each component; the components even could have different types), and each one has to be evaluated. So there is no need to repeat that.
NOTE By the rules given above, for a record_aggregate
with positional associations, expressions specifying discriminant values appear first and in the same order as their corresponding discriminant_specification
s, since the known_discriminant_part
occurs first in the declaration of the type.
Examples
22Example of a record aggregate with positional associations:
(4, July, 1776) -- see 3.8
24
Examples of record aggregates with named associations:
(Day => 4, Month => July, Year => 1776)
(Month => July, Day => 4, Year => 1776)
26
(Disk, Closed, Track => 5, Cylinder => 12) -- see 3.8.1
(Unit => Disk, Status => Closed, Cylinder => 9, Track => 1)
27/2
Examples of component associations with several choices:
(Value => 0, Succ|Pred => new Cell'(0, null, null)) -- see 3.10.1
29
-- The allocator is evaluated twice:
-- Succ and Pred designate different cells
29.1/2
(Value => 0, Succ|Pred => <>) -- see 3.10.1
29.2/2
-- Succ and Pred will be set to null
30
Examples of record aggregates for tagged types (see 3.9 and 3.9.1):
Expression'(null record)
Literal'(Value => 0.0)
Painted_Point'(0.0, Pi/2.0, Paint => Red)
Extensions to Ada 83
Null record aggregates may now be specified, via "(null record)". However, this syntax is more useful for null record extensions in extension aggregates.
Wording Changes from Ada 83
Various AIs have been incorporated (AI83-00189, AI83-00244, and AI83-00309). In particular, Ada 83 did not explicitly disallow extra values in a record aggregate. Now we do.
Extensions to Ada 95
<> can be used in place of an expression
in a record_aggregate
, default initializing the component.
Wording Changes from Ada 95
Limited record_aggregate
s are allowed (since all kinds of aggregates can now be limited, see 4.3).
Incompatibilities With Ada 2005
Corrected wording so that the rule for discriminants governing variant_part
s was not effectively circular. The change makes a few aggregate
s where a nonstatic discriminant governs an empty variant_part
illegal. However, most Ada implementations already enforce some version of the new rule and already reject these aggregate
s. So it is unlikely that any incompatibility will be noticed in practice.
Extensions to Ada 2005
Fixed the wording so that others => <> can be used in place of null record. This is needed to avoid a generic contract issue for generic bodies: we do not want to have to assume the worst to disallow others => <> if the record type might be a null record.
We now allow multiple components with anonymous access types to be specified with a single component association. This is to be consistent with the capabilities of a named access type.
Extensions to Ada 2012
The value of a discriminant that governs a variant_part
in an aggregate
can be nonstatic if the nominal subtype of the discriminant expression is static and all possible values select a single variant
.
Wording Changes from Ada 2012
Corrigendum: We explicitly say that the Legality Rules have to be rechecked for each component individually. This seems obvious, but as the AARM note 4.3.1 (16.c) appeared to say that this was not necessary, and since we explicitly state this sort of thing for generic instances, it seemed better to be explicit.
4.3.2 Extension Aggregates
1[An extension_aggregate
specifies a value for a type that is a record extension by specifying a value or subtype for an ancestor of the type, followed by associations for any components not determined by the ancestor_part
.]
Language Design Principles
The model underlying this syntax is that a record extension can also be viewed as a regular record type with an ancestor "prefix". The record_component_association_list
corresponds to exactly what would be needed if there were no ancestor/prefix type. The ancestor_part
determines the value of the ancestor/prefix.
Syntax
2extension_aggregate
::=
(ancestor_part
with record_component_association_list
)
3
ancestor_part
::=
expression
| subtype_mark
Name Resolution Rules
4/2The expected type for an extension_aggregate
shall be a single type that is a record extension. If the ancestor_part
is an expression
, it is expected to be of any tagged type.
We could have made the expected type T'Class where T is the ultimate ancestor of the type of the aggregate, or we could have made it even more specific than that. However, if the overload resolution rules get too complicated, the implementation gets more difficult and it becomes harder to produce good error messages.
This rule is additive with the rule given in 4.3. That means the 4.3 rule must be satisfied even though it is always syntactically possible to tell that something is an extension aggregate rather than another kind of aggregate. Specifically, that means that an extension aggregate is ambiguous if the context is overloaded on array and/or untagged record types, even though those are never legal contexts for an extension aggregate. Thus, this rule acts more like a Legality Rule than a Name Resolution Rule.
Legality Rules
5/3If the ancestor_part
is a subtype_mark
, it shall denote a specific tagged subtype. If the ancestor_part
is an expression
, it shall not be dynamically tagged. The type of the extension_aggregate
shall be a descendant of the type of the ancestor_part
(the ancestor type), through one or more record extensions (and no private extensions). If the ancestor_part
is a subtype_mark
, the view of the ancestor type from which the type is descended (see 7.3.1) shall not have unknown discriminants.
The expression cannot be dynamically tagged to prevent implicit "truncation" of a dynamically-tagged value to the specific ancestor type. This is similar to the rules in 3.9.2.
If the type of the ancestor_part
is limited and at least one component is needed in the record_component_association_list
, then the ancestor_part
shall not have an operative constituent expression (see 4.4) that is a call to a function with an unconstrained result subtype.
This restriction simplifies implementation, because it ensures that either the caller or the callee knows the size to allocate for the aggregate. Without this restriction, information from both caller and callee would have to be combined to determine the appropriate size.
The (F(...) with null record) case is exempt from this rule, because such extension aggregates are created internally for inherited functions returning null-extension types — we can't very well make those illegal. Moreover, we don't need the rule for null extensions, as the result can simply use the space returned by the function call.
The mention of “operative constituents” means that constructs like parenthesized expressions, qualified_expression
s, and conditional_expression
s are ignored when enforcing this rule.
Static Semantics
6For the record_component_association_list
of an extension_aggregate
, the only components needed are those of the composite value defined by the aggregate that are not inherited from the type of the ancestor_part
, plus any inherited discriminants if the ancestor_part
is a subtype_mark
that denotes an unconstrained subtype.
Dynamic Semantics
7For the evaluation of an extension_aggregate
, the record_component_association_list
is evaluated. If the ancestor_part
is an expression
, it is also evaluated; if the ancestor_part
is a subtype_mark
, the components of the value of the aggregate not given by the record_component_association_list
are initialized by default as for an object of the ancestor type. Any implicit initializations or evaluations are performed in an arbitrary order, except that the expression
for a discriminant is evaluated prior to any other evaluation or initialization that depends on it.
If the type of the ancestor_part
has discriminants and the ancestor_part
is not a subtype_mark
that denotes an unconstrained subtype, then a check is made that each discriminant determined by the ancestor_part
has the value specified for a corresponding discriminant, if any, either in the record_component_association_list
, or in the derived_type_definition
for some ancestor of the type of the extension_aggregate
. Constraint_Error is raised if this check fails.
Corresponding and specified discriminants are defined in 3.7. The rules requiring static compatibility between new discriminants of a derived type and the parent discriminant(s) they constrain ensure that at most one check is required per discriminant of the ancestor expression.
The check needs to be made any time that the ancestor is constrained; the source of the discriminants or the constraints is irrelevant.
NOTE 1 By the rules given in 4.3.1, if all components of the value of the extension_aggregate
are determined by the ancestor_part
, then the record_component_association_list
will be simply null record.
NOTE 2 If the ancestor_part
is a subtype_mark
, then its type can be abstract. If its type is controlled, then as the last step of evaluating the aggregate, the Initialize procedure of the ancestor type is called, unless the Initialize procedure is abstract (see 7.6).
Examples
11Examples of extension aggregates (for types defined in 3.9.1):
Painted_Point'(Point with Red)
(Point'(P) with Paint => Black)
13/5
(Expression with Left => new Literal'(Value => 1.2),
Right => new Literal'(Value => 3.4))
Addition'(Binop with null record)
-- presuming Binop is of type Binary_Operation
Extensions to Ada 83
The extension aggregate syntax is new.
Incompatibilities With Ada 95
Amendment Eliminated implicit “truncation” of a dynamically tagged value when it is used as an ancestor expression
. If an aggregate
includes such an expression
, it is illegal in Ada 2005. Such aggregate
s are thought to be rare; the problem can be fixed with a type conversion to the appropriate specific type if it occurs.
Wording Changes from Ada 95
Limited extension_aggregate
s are allowed (since all kinds of aggregates can now be limited, see 4.3).
Inconsistencies With Ada 2005
An extension_aggregate
with an ancestor_part
whose discriminants are constrained and inherited might now raise Constraint_Error if the aggregate
's type is constrained, while it was OK in Ada 2005. In almost all cases, this will make no difference as the constraint will be checked by the immediately following use of the aggregate
, but it is possible to compare such an aggregate for equality; in this case, no exception would be raised by Ada 2005, while Ada 2012 will raise Constraint_Error. This should be very rare, and having the possibility means that the representation of the aggregate type has to be able to support unconstrained values of the type, even if the first subtype is constrained and no such objects can be created any other way.
Incompatibilities With Ada 2005
A limited unconstrained ancestor expression that is a function call is now illegal unless the extension part is null. Such aggregate
s were first introduced in Ada 2005 and are very complex to implement as they must be built-in-place with an unknown size; as such, it is unlikely that they are implemented correctly in existing compilers and thus not often used in existing code.
An ancestor_part
that is a subtype with unknown discriminants is now explicitly illegal. Such a subtype should not be used to declare an object, and the ancestor_part
acts like an object. The Ada 95 rules did not disallow such cases, so it is possible that code exists that uses such an ancestor, but this should be rare.
Wording Changes from Ada 2012
Rewrote a Legality Rule to use the new term “operative constituent” in order to reduce duplication of text about ignoring parenthesized expressions and similar constructs.
4.3.3 Array Aggregates
1[In an array_aggregate
, a value is specified for each component of an array, either positionally or by its index.] For a positional_array_aggregate
, the components are given in increasing-index order, with a final others, if any, representing any remaining components. For a named_array_aggregate
, the components are identified by the values covered by the discrete_choice
s.
Language Design Principles
The rules in this subclause are based on terms and rules for discrete_choice_list
s defined in 3.8.1, “Variant Parts and Discrete Choices”. For example, the requirements that others come last and stand alone are found there.
Syntax
2/5array_aggregate
::=
positional_array_aggregate
| null_array_aggregate
| named_array_aggregate
3/5
positional_array_aggregate
::=
(expression
, expression
{, expression
})
| (expression
{, expression
}, others => expression
)
| (expression
{, expression
}, others => <>)
| '[' expression
{, expression
}[, others => expression
] ']'
| '[' expression
{, expression
}, others => <> ']'
3.1/5
4/5
named_array_aggregate
::=
(array_component_association_list
)
| '[' array_component_association_list
']'
4.1/5
array_component_association_list
::=
array_component_association
{, array_component_association
}
5/5
array_component_association
::=
discrete_choice_list
=> expression
| discrete_choice_list
=> <>
| iterated_component_association
5.1/5
iterated_component_association
::=
for defining_identifier
in discrete_choice_list
=> expression
| for iterator_specification
=> expression
6
An n-dimensional array_aggregate
is one that is written as n levels of nested array_aggregate
s (or at the bottom level, equivalent string_literal
s). For the multidimensional case (n >= 2) the array_aggregate
s (or equivalent string_literal
s) at the n–1 lower levels are called subaggregates of the enclosing n-dimensional array_aggregate
. The expression
s 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
.
Subaggregates do not have a type. They correspond to part of an array. For example, with a matrix, a subaggregate would correspond to a single row of the matrix. The definition of "n-dimensional" array_aggregate
applies to subaggregates as well as aggregate
s that have a type.
To be honest: An others choice is the reserved word others as it appears in a positional_array_aggregate
or as the discrete_choice
of the discrete_choice_list
in an array_component_association
.
The defining_identifier
of an iterated_component_association
declares an index parameter, an object of the corresponding index type.
Name Resolution Rules
7/2The expected type for an array_aggregate
(that is not a subaggregate) shall be a single array type. The component type of this array type is the expected type for each array component expression of the array_aggregate
.
We already require a single array or record type or record extension for an aggregate
. The above rule requiring a single array type (and similar ones for record and extension aggregates) resolves which kind of aggregate you have.
The expected type for each discrete_choice
in any discrete_choice_list
of a named_array_aggregate
is the type of the corresponding index; the corresponding index for an array_aggregate
that is not a subaggregate is the first index of its type; for an (n–m)-dimensional subaggregate within an array_aggregate
of an n-dimensional type, the corresponding index is the index in position m+1.
Legality Rules
9/5An array_aggregate
of an n-dimensional array type shall be written as an n-dimensional array_aggregate
, or as a null_array_aggregate
.
In an m-dimensional array_aggregate
[(including a subaggregate)], where m >= 2, each of the expression
s has to be an (m–1)-dimensional subaggregate.
An others choice is allowed for an array_aggregate
only if an applicable index constraint applies to the array_aggregate
. [An applicable index constraint is a constraint provided by certain contexts that can be used to determine the bounds of the array value specified by an array_aggregate
.] Each of the following contexts (and none other) defines an applicable index constraint:
- For an
explicit_actual_parameter
, anexplicit_generic_actual_parameter
, theexpression
of a return statement, the return expression of an expression function, the initialization expression in anobject_declaration
, or adefault_expression
[(for a parameter or a component)], when the nominal subtype of the corresponding formal parameter, generic formal parameter, function return object, expression function return object, object, or component is a constrained array subtype, the applicable index constraint is the constraint of the subtype; 12 - For the
expression
of anassignment_statement
where thename
denotes an array variable, the applicable index constraint is the constraint of the array variable;
This case is broken out because the constraint comes from the actual subtype of the variable (which is always constrained) rather than its nominal subtype (which might be unconstrained).
- For the operand of a
qualified_expression
whosesubtype_mark
denotes a constrained array subtype, the applicable index constraint is the constraint of the subtype; 14 - For a component
expression
in anaggregate
, if the component's nominal subtype is a constrained array subtype, the applicable index constraint is the constraint of the subtype;
Here, the array_aggregate
with others is being used within a larger aggregate.
- For the base_
expression
of adelta_aggregate
, if the nominal subtype of thedelta_aggregate
is a constrained array subtype, the applicable index constraint is the constraint of the subtype; 15/3 - For a parenthesized
expression
, the applicable index constraint is that, if any, defined for theexpression
;
RM83 omitted this case, presumably as an oversight. We want to minimize situations where an expression
becomes illegal if parenthesized.
- For a
conditional_expression
(see 4.5.7), the applicable index constraint for each dependent_expression
is that, if any, defined for theconditional_expression
; 15.2/5 - For a
declare_expression
(see 4.5.9), the applicable index constraint for the body_expression
is that, if any, defined for thedeclare_expression
.
The applicable index constraint applies to an array_aggregate
that appears in such a context, as well as to any subaggregates thereof. In the case of an explicit_actual_parameter
(or default_expression
) for a call on a generic formal subprogram, no applicable index constraint is defined.
This avoids generic contract model problems, because only mode conformance is required when matching actual subprograms with generic formal subprograms.
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 either there is only one array_component_association
in the enclosing array_component_association_list
or the enclosing aggregate
is an array_delta_aggregate
[, not an array_aggregate
].
We now allow a nonstatic others choice even if there are other array component expressions as well.
We allow multiple dynamic choices in array_delta_aggregate
s, but only one dynamic choice per association even in that case.
Either all or none of the array_component_association
s of an array_component_association_list
shall be iterated_component_association
s with an iterator_specification
.
In a named_array_aggregate
where all discrete_choice
s are static, no two discrete_choice
s are allowed to cover the same value (see 3.8.1); if there is no others choice, the discrete_choice
s taken together shall exactly cover a contiguous sequence of values of the corresponding index type.
This implies that each component must be specified exactly once. See AI83-309.
This has to apply even if there is only one static discrete_choice
; a single choice has to represent a contiguous range (a subtype_mark
with a static predicate might represent a discontiguous set of values). If the (single) choice is a dynamic subtype, we don't need to make this check as no predicates are allowed (see 3.2.4) and thus the range has to be contiguous.
A bottom level subaggregate of a multidimensional array_aggregate
of a given array type is allowed to be a string_literal
only if the component type of the array type is a character type; each character of such a string_literal
shall correspond to a defining_character_literal
of the component type.
Static Semantics
20A 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
.
To be honest: This is true even in cases where there is no corresponding legal positional_array_aggregate
.
The subtype (and nominal subtype) of an index parameter is the corresponding index subtype.
Dynamic Semantics
20.2/5For an array_aggregate
that contains only array_component_association
s that are iterated_component_association
s with iterator_specification
s, evaluation proceeds in two steps:
1.
- 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); 20.4/5
2.- A second iteration is performed for each of the
iterator_specification
s, in the order given in theaggregate
, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2), the associatedexpression
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.
To be honest: Constraint_Error should be raised no later than when the iterations exceed the maximum array length; memory that doesn't belong to the aggregate temporary should not be overwritten.
The evaluation of any other array_aggregate
of a given array type proceeds in two steps:
1.
- Any
discrete_choice
s of this aggregate and of its subaggregates are evaluated in an arbitrary order, and converted to the corresponding index type; 23
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.
Subaggregates are not separately evaluated. The conversion of the value of the component expressions to the component subtype might raise Constraint_Error.
We don't need to say that <> is evaluated once for each component, as <> means that each component is initialized by default. That means that the actions defined for default initialization are applied to each component individually. Initializing one component by default and copying that to the others would be an incorrect implementation in general (although it might be OK if the default initialization is known to be constant).
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).
During an evaluation of the expression
of an iterated_component_association
with a discrete_choice_list
, the value of the corresponding index parameter is that of the corresponding index of the corresponding array component. During an evaluation of the expression
of an iterated_component_association
with an iterator_specification
, the value of the loop parameter of the iterator_specification
is the value produced by the iteration (as described in 5.5.2).
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 of an iterated_component_association
can take on its values in an arbitrary order. This is different from other constructs, such as a loop_statement
. In contrast, a loop parameter of an iterated_component_association
takes its values in the order defined by the iteration, the same as a loop_statement
.
The bounds of the index range of an array_aggregate
[(including a subaggregate)] are determined as follows:
- For an
array_aggregate
with an others choice, the bounds are those of the corresponding index range from the applicable index constraint; 26 - For a
positional_array_aggregate
[(or equivalentstring_literal
)] without an others choice, the lower bound is that of the corresponding index range in the applicable index constraint, if defined, or that of the corresponding index subtype, if not; in either case, the upper bound is determined from the lower bound and the number ofexpression
s [(or the length of thestring_literal
)]; 26.1/5 - For a
null_array_aggregate
, bounds for each dimension are determined as for apositional_array_aggregate
without an others choice that has no expressions for each dimension;
We need a separate rule to describe what happens for a multidimensional null_array_aggregate
; we could've combined the single-dimension case with the positional_array_aggregate
rule.
- For a
named_array_aggregate
containing onlyiterated_component_association
s with aniterator_specification
, the lower bound is determined as for apositional_array_aggregate
without an others choice, and the upper bound is determined from the lower bound and the total number of values produced by the second set of iterations; 27/5 - For any other
named_array_aggregate
without an others choice, the bounds are determined by the smallest and largest index values covered by anydiscrete_choice_list
.
We don't need to say that each index value has to be covered exactly once, since that is a ramification of the general rule on aggregate
s that each component's value has to be specified exactly once.
For an array_aggregate
, a check is made that the index range defined by its bounds is compatible with the corresponding index subtype.
In RM83, this was phrased more explicitly, but once we define "compatibility" between a range and a subtype, it seems to make sense to take advantage of that definition.
The definition of compatibility handles the special case of a null range, which is always compatible with a subtype. See AI83-00313.
For an array_aggregate
with an others choice, a check is made that no expression
or <> is specified for an index value outside the bounds determined by the applicable index constraint.
RM83 omitted this case, apparently through an oversight. AI83-00309 defines this as a dynamic check, even though other Ada 83 rules ensured that this check could be performed statically. We now allow an others choice to be dynamic, even if it is not the only choice, so this check now needs to be dynamic, in some cases. Also, within a generic unit, this would be a nonstatic check in some cases.
For a multidimensional array_aggregate
, a check is made that all subaggregates that correspond to the same index have the same bounds.
No array bounds “sliding” is performed on subaggregates.
If sliding were performed, it would not be obvious which subaggregate would determine the bounds of the corresponding index.
The exception Constraint_Error is raised if any of the above checks fail.
Implementation Permissions
32/5When evaluating iterated_component_association
s for an array_aggregate
that contains only iterated_component_association
s with iterator_specification
s, the first step of evaluating an iterated_component_association
can be omitted if the implementation can determine the maximum number of values by some other means.
For instance, if the type of the aggregate is constrained, the implementation can (but does not have to) calculate the expected length from the constraint.
NOTE 1 In an array_aggregate
delimited by parentheses, positional notation can only be used with two or more expression
s; a single expression
in parentheses is interpreted as a parenthesized expression. An array_aggregate
delimited by square brackets can be used to specify an array with a single component.
Examples
35Examples of array aggregates with positional associations:
(7, 9, 5, 1, 3, 2, 4, 8, 6, 0)
Table'(5, 8, 4, 1, others => 0) -- see 3.6
37
Examples of array aggregates with named associations:
(1 .. 5 => (1 .. 8 => 0.0)) -- two-dimensional
[1 .. N => new Cell] -- N new cells, in particular for N = 0
39/5
Table'(2 | 4 | 10 => 1, others => 0)
Schedule'(Mon .. Fri => True, others => False) -- see 3.6
Schedule'[Wed | Sun => False, others => True]
Vector'(1 => 2.5) -- single-component vector
40
Examples of two-dimensional array aggregates:
-- Three aggregates for the same value of subtype Matrix(1..2,1..3) (see 3.6):
42/5
((1.1, 1.2, 1.3), (2.1, 2.2, 2.3))
(1 => [1.1, 1.2, 1.3], 2 => [2.1, 2.2, 2.3])
[1 => (1 => 1.1, 2 => 1.2, 3 => 1.3),
2 => (1 => 2.1, 2 => 2.2, 3 => 2.3)]
43
Examples of aggregates as initial values:
A : Table := (7, 9, 5, 1, 3, 2, 4, 8, 6, 0); -- A(1)=7, A(10)=0
B : Table := (2 | 4 | 10 => 1, others => 0); -- B(1)=0, B(10)=1
C : constant Matrix := (1 .. 5 => (1 .. 8 => 0.0));
-- C'Last(1)=5, C'Last(2)=8
45
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"
46/5
G : constant Matrix :=
(for I in 1 .. 4 =>
(for J in 1 .. 4 =>
(if I=J then 1.0 else 0.0))); -- Identity matrix
47/5
Empty_Matrix : constant Matrix := []; -- A matrix without elements
48/2
Example of an array aggregate with defaulted others choice and with an applicable index constraint provided by an enclosing record aggregate:
Buffer'(Size => 50, Pos => 1, Value => ('x', others => <>)) -- see 3.7
Incompatibilities With Ada 83
In Ada 95, no applicable index constraint is defined for a parameter in a call to a generic formal subprogram; thus, some aggregates that are legal in Ada 83 are illegal in Ada 95. For example:
subtype S3 is String (1 .. 3);
...
generic
with function F (The_S3 : in S3) return Integer;
package Gp is
I : constant Integer := F ((1 => '!', others => '?'));
-- The aggregate is legal in Ada 83, illegal in Ada 95.
end Gp;
This change eliminates generic contract model problems.
Extensions to Ada 83
We now allow "named with others" aggregates in all contexts where there is an applicable index constraint, effectively eliminating what was RM83-4.3.2(6). Sliding never occurs on an aggregate with others, because its bounds come from the applicable index constraint, and therefore already match the bounds of the target.
The legality of an others choice is no longer affected by the staticness of the applicable index constraint. This substantially simplifies several rules, while being slightly more flexible for the user. It obviates the rulings of AI83-00244 and AI83-00310, while taking advantage of the dynamic nature of the "extra values" check required by AI83-00309.
Named array aggregates are permitted even if the index type is descended from a formal scalar type. See 4.9 and AI83-00190.
Wording Changes from Ada 83
We now separate named and positional array aggregate syntax, since, unlike other aggregates, named and positional associations cannot be mixed in array aggregates (except that an others choice is allowed in a positional array aggregate).
We have also reorganized the presentation to handle multidimensional and one-dimensional aggregates more uniformly, and to incorporate the rulings of AI83-00019, AI83-00309, etc.
Extensions to Ada 95
<> can be used in place of an expression
in an array_aggregate
, default-initializing the component.
Wording Changes from Ada 95
Limited array_aggregate
s are allowed (since all kinds of aggregates can now be limited, see 4.3).
Fixed aggregate
s to use the subtype of the return object of a function, rather than the result subtype, because they can be different for an extended_return_statement
, and we want to use the subtype that's explicitly in the code at the point of the expression
.
Inconsistencies With Ada 2005
Fixed so the check for components outside of the array applies to both expression
s and <>s. As <> was a new feature in Ada 2005, there should be little existing code that depends on a <> component that is specified outside of the array (and that is nonsense anyway, that a compiler is likely to detect even without an explicit language rule disallowing it).
Wording Changes from Ada 2005
Added a definition of the applicable index constraint for conditional_expression
s (which are new).
Inconsistencies With Ada 2012
Corrigendum: Fixed so that the Default_Component_Value (if any) is used to initialize components specified with <>. This is what users would expect, and all Ada 2012 implementation known at the time of this writing initialize with the Default_Component_Value, so it is unlikely that anyone will be affected by this inconsistency.
Extensions to Ada 2012
The iterated_component_association
is new (more than 25 years after it was originally proposed). It has been extended to allow container iterators as well as the basic index iterators.
An array_aggregate
can be surrounded by brackets rather than parentheses. This allows consistent writing of zero- and one-component positional array aggregates, and is consistent with the syntax for writing container aggregates.
Wording Changes from Ada 2012
Corrigendum: Added expression functions to the contexts that provide an applicable index constraint, because expression functions are handled separately in static semantics and legality rules.
Added a definition of the applicable index constraint for declare_expression
s (which are new). This allows others in array aggregates inside of declare_expression
s.
4.3.4 Delta Aggregates
1/5Evaluating a (record or array) delta aggregate yields a composite value that starts with a copy of another value of the same type and then assigns to some (but typically not all) components of the copy.
Syntax
2/5delta_aggregate
::=
record_delta_aggregate
| array_delta_aggregate
3/5
record_delta_aggregate
::=
(base_expression
with delta record_component_association_list
)
4/5
array_delta_aggregate
::=
(base_expression
with delta array_component_association_list
)
| '[' base_expression
with delta array_component_association_list
']'
Name Resolution Rules
5/5The expected type for a record_delta_aggregate
shall be a single descendant of a record type or record extension.
The expected type for an array_delta_aggregate
shall be a single array type.
The expected type for the base_expression
of any delta_aggregate
is the type of the enclosing delta_aggregate
.
[The Name Resolution Rules and Legality Rules for each record_component_association
of a record_delta_aggregate
are as defined in 4.3.1.]
For an array_delta_aggregate
, the expected type for each discrete_choice
in an array_component_association
is the index type of the type of the delta_aggregate
.
The expected type of the expression
in an array_component_association
is defined as for an array_component_association
occurring within an array_aggregate
of the type of the delta_aggregate
.
Legality Rules
11/5For an array_delta_aggregate
, the array_component_association
shall not use the box symbol <>, and the discrete_choice
shall not be others.
For an array_delta_aggregate
, the dimensionality of the type of the delta_aggregate
shall be 1.
For an array_delta_aggregate
, the base_expression
and each expression
in every array_component_association
shall be of a nonlimited type.
The base_expression
of a record_delta_aggregate
may be of a limited type (for example a record with limited components), as it is not restricted. A rule in 4.3.1 ensures that we do not assign to a limited component. We do not allow any part of an array_delta_aggregate
to be of a limited type, even the base_expression
, as this is a useless construct (you would not be able to update anything because the components necessarily are also limited except in pathological cases).
Dynamic Semantics
14/5The evaluation of a delta_aggregate
begins with the evaluation of the base_expression
of the delta_aggregate
; then that value is used to create and initialize the anonymous object of the aggregate
. The bounds of the anonymous object of an array_delta_aggregate
and the discriminants (if any) of the anonymous object of a record_delta_aggregate
are those of the base_expression
. If a record_delta_aggregate
is of a specific tagged type, its tag is that of the specific type; if it is of a class-wide type, its tag is that of the base_expression
.
This is the same anonymous object as described in 7.6, “Assignment and Finalization”; in particular, it might be required to be built in place.
For a specific tagged type, any extension components that the actual object underlying the base_expression
might have are not used to initialize the anonymous object, which is critical if the aggregate is required to be built-in-place.
To be honest: The anonymous object associated with the evaluation of a delta_aggregate
begins its life as a variable, not a constant (3.3 notwithstanding). This must be the case because the object is initialized and then subsequently modified. After evaluation of the delta_aggregate
is complete, the object is a constant object. This is similar to the way that an extended return statement can provide a variable view of an object that will eventually be a constant object after the function returns its result.
For a record_delta_aggregate
, for each component associated with each record_component_association
(in an unspecified order):
- if the associated component belongs to a
variant
, a check is made that the values of the discriminants are such that the anonymous object has this component. The exception Constraint_Error is raised if this check fails. 17/5 - the
expression
of therecord_component_association
is evaluated, converted to the nominal subtype of the associated component, and assigned to the component of the anonymous object.
For an array_delta_aggregate
, for each discrete_choice
of each array_component_association
(in the order given in the enclosing discrete_choice_list
and array_component_association_list
, respectively) the discrete_choice
is evaluated; for each represented index value (in ascending order, if the discrete_choice
represents a range):
- the index value is converted to the index type of the array type.
- a check is made that the index value belongs to the index range of the anonymous object of the
aggregate
; Constraint_Error is raised if this check fails. 21/5 - the component
expression
is evaluated, converted to the array component subtype, and assigned to the component of the anonymous object identified by the index value.
Unlike other aggregate
s, an array_delta_aggregate
is evaluated in the order that it is written. This is necessary to get deterministic behavior, as (unlike other aggregate
s, including record_delta_aggregate
s) there is no requirement that the specified components be distinct. As such, the order requirement ensures that every array_delta_aggregate
has a well-defined result, even if the same component is specified multiple times.
Examples
22/5Examples of use of delta aggregates in a postcondition:
procedure Twelfth (D : in out Date) -- see 3.8 for type Date
with Post => D = (D'Old with delta Day => 12);
24/5
procedure The_Answer (V : in out Vector;
A, B : in Integer) -- see 3.6 for type Vector
with Post => V = (V'Old with delta A .. B => 42.0, V'First => 0.0);
25/5
Examples where the base expression is nontrivial:
New_Cell : Cell := (Min_Cell (Head) with delta Value => 42);
-- see 3.10.1 for Cell and Head; 6.1 for Min_Cell
27/5
A1 : Vector := ((0 => 1.0, 1 => 2.0, 2 => 3.0)
with delta Integer(Random * 2.0) => 14.2);
-- see 3.6 for declaration of type Vector
-- see 6.1 for declaration of Random
28/5
Tomorrow := ((Yesterday with delta Day => 12)
with delta Month => April); -- see 3.8
29/5
Example where the base expression is class-wide:
function Translate (P : Point'Class; X, Y : Real) return Point'Class is
(P with delta X => P.X + X,
Y => P.Y + Y); -- see 3.9 for declaration of type Point
Extensions to Ada 2012
4.3.5 Container Aggregates
1/5In 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.
Term entry: container aggregate — construct used to define a value of a type that represents a collection of elements, by explicitly specifying the elements in the collection
For a type other than an array type, the following type-related operational aspect may be specified:
Aggregate
- This aspect is an
aggregate
of the form:
Aspect Description for Aggregate: Mechanism to define user-defined aggregates.
(Empty => name
[,
Add_Named => procedure_name
][,
Add_Unnamed => procedure_name
][,
New_Indexed => function_name
,
Assign_Indexed => procedure_name
])
As this aspect is described with syntax, it has to be given exactly as specified here. That means it cannot be given as a positional aggregate, nor can the order of the elements be changed. For instance, New_Indexed always has to occur before Assign_Indexed, and Empty always has to be first.
- 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/5The 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.
In the function case, the parameter, if present may be used to specify an initial size for the container, in anticipation of adding elements to it. For a positional aggregate, or a named aggregate that doesn't use an iterator, it will be initialized with the number of elements. For a named aggregate that uses an iterator, the implementation is permitted to estimate the number of elements that the iterator will produce, but it is not required to do so.
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.
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.
The New_Indexed function is used instead of Empty as the first step of creating an aggregate that is initialized using the Assign_Indexed procedure.
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/5If 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.
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/5The Aggregate aspect is nonoverridable (see 13.1.1).
Syntax
13/5container_aggregate
::=
null_container_aggregate
| positional_container_aggregate
| named_container_aggregate
14/5
15/5
positional_container_aggregate
::=
'[' expression
{, expression
} ']'
16/5
named_container_aggregate
::=
'[' container_element_association_list
']'
Unlike other aggregate
s, container aggregates have to be surrounded with brackets rather than parentheses. Using brackets allows writing zero- and one-element positional aggregate
s. (Were we to use parentheses, a one-element positional aggregate would look the same as and would always be interpreted as a parenthesized expression.) Unlike the case for arrays, where it is always possible to give bounds to work around this gap, such an aggregate
could not be written at all for a sequence type (such as a list) where there is no index or key to use.
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/5The 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.
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/5The 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_association
s 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_list
s 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.]
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.
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.
Only an element of an indexed aggregate can be left uninitialized, because the compiler can simply omit producing an Assign_Indexed operation for the given index. For other kinds of aggregates, there are no operations that add an element without giving it a value. We could have defined such (optional) operations, but they would have added significant complication to an already complex feature without adding much additional expressive power. Note that, to be consistent with array aggregates, we do not support specifying <> in an iterated_element_association
.
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
.
If there is a key_expression
in an iterated_element_association
, it determines the key of each added key/value pair, rather than the loop parameter. But if there is no key_expression
, the loop parameter itself is used as the key.
For a named_container_aggregate
that is an indexed aggregate, all container_element_association
s 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:
- all
key_choice
s shall be static expressions or static ranges, and everyloop_parameter_specification
shall have adiscrete_subtype_definition
that defines a non-null static range, and the set of values of the index type covered by thekey_choice
s and thediscrete_subtype_definition
s 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 akey_choice_list
, the list shall have exactly onekey_choice
.
The above is trying to mimic the rules for named_array_aggregate
s, without others.
Dynamic Semantics
31/5The evaluation of a container_aggregate
starts by creating an anonymous object A of the expected type T, initialized as follows:
- 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 theaggregate
, and are determined as follows: 33/5 - if the
aggregate
is apositional_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 ofexpression
s in theaggregate
; 34/5 - if the
aggregate
is anamed_container_aggregate
, the lower bound is the lowest value covered by akey_choice_list
or is the low bound of a range defined by adiscrete_subtype_definition
of aloop_parameter_specification
; the upper bound is the highest value covered by akey_choice_list
or is the high bound of a range defined by adiscrete_subtype_definition
of aloop_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 ofexpression
s; 38/5 - for a
named_container_aggregate
without aniterated_element_association
, the number of key_expression
s; 39/5 - for a
named_container_aggregate
where everyiterated_element_association
contains aloop_parameter_specification
, the total number of elements specified by all of thecontainer_element_association
s; 40/5 - otherwise, to an implementation-defined value.
This value ought to be an estimate for the number of elements in the aggregate
, if one is available. If not, it is suggested to use the default value for the parameter if one exists, and zero otherwise.
The value of the parameter to Empty for some container_aggregate
s.
The evaluation then proceeds as follows:
- 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, eachexpression
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 eachexpression
as the second parameter, in the order of theexpression
s; 44/5 - for a
positional_container_aggregate
that is an indexed aggregate, eachexpression
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 successiveexpression
, and the result of evaluating eachexpression
as the third parameter; 45/5 - for a
named_container_aggregate
for a type with an Add_Named procedure in its Aggregate aspect, thecontainer_element_association
s are evaluated in an arbitrary order: 46/5 - for a
container_element_association
with akey_choice_list
, for eachkey_choice
of the list in an arbitrary order, thekey_choice
is evaluated as is theexpression
of thecontainer_element_association
(in an arbitrary order), and the Add_Named procedure is invoked once for each value covered by thekey_choice
, with the anonymous object A as the first parameter, the value from thekey_choice
as the second parameter, and the result of evaluating theexpression
as the third parameter; 47/5 - for a
container_element_association
with aniterated_element_association
, first theiterated_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 theexpression
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;
- 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 acontainer_element_association
with a <> rather than anexpression
, 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
, thecontainer_element_association
s (which are necessarilyiterated_element_association
s) are evaluated in the order given; each such evaluation comprises two steps:
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.
In this case, the value of the loop parameter is not directly relevant, though presumably it appears within the expression
of the iterated_element_association
.
Examples
54/5Examples of specifying the Aggregate aspect for a Set_Type, a Map_Type, and a Vector_Type:
-- 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:
-- 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_associations:
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");