Version 1.7 of ai12s/ai12-0212-1.txt

Unformatted version of ai12s/ai12-0212-1.txt version 1.7
Other versions for file ai12s/ai12-0212-1.txt

!standard 4.3.5(0)          18-01-24 AI12-0212-1/02
!class Amendment 16-12-27
!status work item 17-06-10
!status received 16-06-12
!priority Low
!difficulty Hard
!subject Container aggregates
!summary
Add aggregate syntax to construct container instances.
!problem
Currently, there are very few constructors for containers. We have for example the constant Empty_Set, and To_Set to construct a set containing the specified element. The best way to do this now is to manually assemble a new container with a series of statements; but this has a number of issues:
- cannot be used in a subprogram contract (such as a post condition) - can make code harder to read since construction has to be moved to a
separate function
An obvious approach would be to add functions that initialise a container from an aggregate of an unconstrained array, for example:
X : Example.Set := Example.From_Array ((1, 2, 3));
However there are a number of drawbacks: the syntax is ugly (double brackets), it would not allow comprehensions (i.e. containers defined by a nested iterator) (only displays -- i.e. an explicit list of components), and it would only work for array-like containers and not maps.
There are three places where container aggregates may be useful: in ordinary code (but here we can just do what we do right now), for the definition of constants, and in contracts.
!proposal
Thus, we propose to add new aspect (in the spirit of Constant_Indexing, Default_Iterator, and Iterator_Element) along with two new aggregates to use it.
This proposal works for most of the standard containers (Vectors, Doubly_Linked_Lists, Hashed_Sets, Ordered_Sets, Hashed_Maps and Ordered_Maps including their bounded and indefinite versions). Multiway_Trees are not supported by this proposal.
The syntax is highly inspired by Python (please do not let that put you off), it just is more Ada-like than comprehension in, say, Haskell.
In the most simple form (called a positional container aggregate) we just give the elements to add in a form very similar to a simple array aggregate:
X : My_Set := (1, 2, 3);
-- Equivalent to: X : My_Set := Empty_Set; Include (X, 1); Include (X, 2); Include (X, 3);
The function or constant "Empty_Set" is one of the two things you specify in the Aggregate aspect, the procedure "Include" is the other.
Positional container aggregates are good for defining simple container instances, but often, you might want to derive one container from another (a concept that is called comprehension). This is vaguely related to a delta aggregate, but neither construct can easily emulate the other.
Here we loop over one container and apply some function to each item. Thy proposed syntax steals from existing loop and quantifier syntax:
Y : My_Set := (for Item of X => Item * 2);
-- Equivalent to: Y : My_Set := Empty_Set; for Item of X loop Include (Y, Item * 2); end loop;
We may also wish to filter the items:
Z : My_Set := (for Item of X when Item > 1 => Item - 1);
-- Equivalent to: Z : My_Set := Empty_Set; for Item of X loop if Item > 1 then Include (Z, Item - 1); end if; end loop;
Finally, it is also a common pattern to combine multiple containers into one. Two approaches are supported. This is the nested (or "product") one:
W : My_Set := (for A of X => for B of X => A * B); -- TBD: Not currently in this AI
-- Equivalent to: W : My_Set := Empty_Set; for A of X loop for B of X loop Include (W, A * B); end loop; end loop;
This is the sequential (or "list") one:
V : My_Set := (for A of X => A, for A of X => -A);
-- Equivalent to: V : My_Set := Empty_Set; for A of X loop Include (V, A); end loop; for A of X loop Include (V, -A); end loop;
This is the concurrent one (TBD -- not in this AI yet):
V : My_Set := (for (A of X; I in 1..Max) => (A, I)); -- TBD: Not currently in this AI yet
-- Equivalent to: V : My_Set := Empty_Set; for (A of X; I in 1..Max) loop Include (V, (A, I)); end loop;
-- where the parenthesized iterators run concurrently, with the iteration -- stopping when either runs out of elements.
The new contract on the set container would be:
type Set is tagged private with -- currently we have this: Constant_Indexing => Constant_Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, -- this is new Aggregate => (Empty => Empty_Set, Add_Positional => Include);
For containers such as maps, an Add_Named component of the Aggregate aspect would be specified, to enable a usage such as:
M : My_Map := (42 => "foo", 88 => "bar");
So, to summarise: * New aspect on types specifying an empty default, plus either an
Add_Positional or an Add_Named procedure (or both).
* Extend aggregate syntax to trigger these
Related changes:
This AI will have some interesting interplay with declare expressions and generators.
!wording
4.3 Aggregates (Syntax)
Change paragraph 2/5:
aggregate ::= record_aggregate | extension_aggregate | array_aggregate | delta_aggregate
To:
aggregate ::= record_aggregate | extension_aggregate | array_aggregate | delta_aggregate | container_aggregate
Modify paragraph 3/5:
The expected type for a delta_aggregate shall be a single array type, or a single descendant of a record type or of a record extension. The expected type for any other aggregate shall be a single array type, record type, [or ]record extension{, or other composite type with the Aggregate aspect specified}.
Add new section: 4.3.5 Container Aggregates
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.
Given a private type or private extension T, the following type-related operational aspect may be specified:
AARM Reason: We require the type to be a partial view so it is clear that the aggregate should not be interpreted as some other kind of aggregate, since syntactically it is indistinguishable.
Aggregate
This aspect is of the form:
(Empty => name[, Add_Positional => /procedure_/name][, Add_Named => /procedure_/name])
Either Add_Positional, Add_Named, or both shall be specified.
Name Resolution Rules
The name specified for Empty shall denote a constant of type T, or denote a function with a result type of T that has no parameters, or that has one IN parameter of type Integer with a default expression.
AARM Reason: 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_Positional, if any, shall have two parameters, the first an IN OUT parameter of type T, and the second an IN parameter of some nonlimited type, called the /element type/ of T.
The /procedure_/name specified for Add_Named, if any, shall have three parameters, the first an IN OUT parameter of type T, the second an IN parameter of a nonlimited type, that is called the /key type/ of the container, and the third, an IN parameter of a nonlimited type that is called the /element type/ of T.
If both Add_Positional and Add_Named are specified, the final parameters shall be of the same type -- the element type of T.
Syntax
container_aggregate ::= positional_container_aggregate | named_container_aggregate
positional_container_aggregate ::= (expression, expression {, expression)
named_container_aggregate ::= (container_element_association_list)
container_element_association_list ::= container_element_association {, container_element_association}
container_element_association ::= key_expression_list => expression | iterated_element_association
key_expression_list ::= /key_/expression {| /key_/expression}
iterated_element_association ::= for loop_parameter_specification[, /key_/expression] => expression | for iterator_specification[, /key_/expression] => expression
Name Resolution Rules
The expected type for a container_aggregate shall be a 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 positional_container_aggregate shall have an Aggregate aspect that includes a specification for an Add_Positional procedure. The expected type for a named_container_aggregate that has one or more /key_/expressions shall have an Aggregate aspect that includes a specification for the Add_Named procedure. The expected type for each such /key_/expression is the key type of the expected type.
Legality Rules
For an iterated_element_association without a /key_/expression, if the expected type T of the aggregate does not specify an Add_Positional 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 T.
AARM Ramification: 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. If there is no /key_/expression, the loop parameter itself is used as the key.
Dynamic Semantics
The evaluation of a container_aggregate starts by creating an anonymous object A of the expected type T initialized 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, the parameter, if any, is initialized as follows:
* for a positional_container_aggregate, the number of expressions;
* for a named_container_aggregate without an iterated_element_association, the number of container_element_associations;
* otherwise, to an implementation-defined value.
The evaluation then proceeds as follows:
* for a positional_container_aggregate, each expression is evaluated in any order, and the Add_Positional procedure is invoked in sequence with the anonymous object A as the first parameter and the result of evaluating each expression in the order of the expressions;
* for a named_container_aggregate for a type with an Add_Named procedure in its Aggregate aspect, the container_element_associations are evaluated in any order:
* for a container_element_association with a key_expression_list, for each /key_/expression of the list in any order, the /key_/expression is evaluated as is the expression of the container_element_association (in any order), and the Add_Named procedure is invoked with the anonymous object A as the first parameter, the result of evaluating the /key_/expression as the second parameter, and the result of evaluating the expression as the third parameter;
* for a container_element_association with an iterated_element_association, the iterated_element_association is elaborated, and an iteration is performed, and for each value of the loop parameter of the iteration 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:
* if there is a /key_/expression, the result of evaluating the /key_/expression as the second parameter;
* otherwise, with the loop parameter as the second parameter;
* for a named_container_aggregate for a type without an Add_Named procedure in its Aggregate aspect, the container_element_associations (which are necessarily iterated_element_associations) are evaluated in the order given:
* the iterated_element_association is elaborated, and an iteration is performed, and for each value of the loop parameter of the iteration, the Add_Positional procedure is invoked with the anonymous object A as the first parameter, and the result of evaluating the expression as the second parameter. AARM Ramification: 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
I KNOW I NEED TO REWORK THESE TO USE EXISTING THINGS IN THE RM
-- Declares a container type. type Set_Type is private
with Aggregate => (Empty => Empty_Set;
Add_Positional => Merge);
function Empty_Set return Set_Type;
procedure Merge (S : in out Set_Type; N : Integer) with Pre => N in 0 .. 1000;
private
type Set_Type is array (0 .. 1000) of Boolean
function Empty_Set return Set_Type is (others => False);
-- A positional set aggregate S := (1, 2);
-- is Equivalent to: S := Empty_Set; S.Include (1); S.Include (2);
-- A named map aggregate M := (12 => "house", 14 => "beige");
-- A set aggregate with an iterated_element_association S := (for Item in 1 .. 5 => Item * 2)
-- is equivalent to S := Empty_Set; for Item in 1 .. 5 loop S.Include (Item * 2); end loop;
-- A set aggregate with a filter (separate AI) S := (for Item in 1 .. 100 when Is_Prime (Item) => Item);
-- is equivalent to S := Empty_Set; for Item in 1 .. 5 loop if Is_Prime then S.Include (Item); end if; end loop;
-- A set aggregate consisting out of two iterated_element_associations S := (for Item in 1 .. 5 => Item, for Item in 1 .. 5 => -Item);
-- Is (mostly, assuming set semantics) equivalent to S := (for Item in -5 .. 5 when Item /= 0 => Item);
-- A set aggregate with more than one item_selector (a TBD AI) S := (for X in 1 .. 10 => for Y in -1 .. 1 when Y /= 0 => X * Y);
-- is equivalent to S := Empty_Set; for X in 1 .. 10 loop for Y in -1 .. 1 loop if Y /= 0 then S.Include (X * Y); end if; end if; end if;
-- An example that combines all aspects of the grammar S := (for Customer of Customer_Database when not Customer.Poor => Customer.Name, for Manager of Managers => for Staff of Manager.Minions when Staff.Performance >= 3.0 => Staff.First_Name & Staff.Last_Name);
-- Is equivalent to S := Empty_Set; for Customer of Customer_Database loop if not Customer.Poor => S.Include (Customer.Name); end if; end loop; for Manager of Managers loop for Staff of Manager.Minions loop if Staff.Performance => 3.0 then S.Include (Staff.First_Name & Staff.Last_Name); end if; end loop; end loop;
A.18.2 The Generic Package Containers.Vectors
Add the Aggregate aspect to the existing ones on type Vector:
type Vector is tagged private with Constant_Indexing => Constant_Reference, Variable_Indexing => Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_Vector, Add_Positional => Append);
A.18.3 The Generic Package Containers.Doubly_Linked_Lists
Add the Aggregate aspect to the existing ones on type List:
type List is tagged private with Constant_Indexing => Constant_Reference, Variable_Indexing => Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_List, Add_Positional => Append);
A.18.5 The Generic Package Containers.Hashed_Maps
Add the Aggregate aspect to the existing ones on type Map:
type Map is tagged private with Constant_Indexing => Constant_Reference, Variable_Indexing => Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_Map, Add_Named => Insert);
A.18.6 The Generic Package Containers.Ordered_Maps
Add the Aggregate aspect to the existing ones on type Map:
type Map is tagged private with Constant_Indexing => Constant_Reference, Variable_Indexing => Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_Map, Add_Named => Insert);
A.18.8 The Generic Package Containers.Hashed_Sets
Add the Aggregate aspect to the existing ones on type Set:
type Set is tagged private with Constant_Indexing => Constant_Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_Set, Add_Positional => Include);
A.18.9 The Generic Package Containers.Ordered_Sets
Add the Aggregate aspect to the existing ones on type Set:
type Set is tagged private with Constant_Indexing => Constant_Reference, Default_Iterator => Iterate, Iterator_Element => Element_Type, Aggregate => (Empty => Empty_Set, Add_Positional => Include);
!discussion
!ASIS
!ACATS test
ACATS B and C-Tests are needed to check that the new capabilities are supported.
!appendix

[Editor's note: This idea originated during ARG meeting #55 in Pisa,
during the discussion of AI12-0189-1,
see http://www.ada-auth.org/ai-files/minutes/min-1606.html#AI189]

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

From: Tucker Taft
Sent: Tuesday, October 11, 2016  12:04 PM

Hi Randy and Jeff,
    Thanks both of you for your great job organizing and running the ARG in
Pittsburgh.

We talked about container aggregates several times.  I see it is on Steve's
plate officially.  Did such an AI ever get created?  Raphael has expressed
an interest in helping on this one...

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

From: Steve Baird
Sent: Wednesday, October 12, 2016  12:30 PM

Container aggregates are on Florian's plate with a promise of assistance from
me (like what we did with delta aggregates).

See Pisa minutes.

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

From: Raphael Amiard
Sent: Tuesday, October 11, 2016  12:04 PM

Florian depending on the quantity of homework you have I'd be happy to help
out or even take over this one. Just tell me :)

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

From: Florian Schanda
Sent: Monday, October 17, 2016  7:02 AM

I have it indeed in my personal notes as an action on me (and I will enlist
the help of Steve et al).

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

From: Florian Schanda
Sent: Saturday, June 10, 2017  3:58 AM

Steve,

I know it said "with help from Steve" but I didn't really ask you for anything
since I was somewhat disorganized this interval. Sorry! However, you will
notice that the proposal includes a number of cries for help now, but I
figured I should post something vaguely substantial so we have a starting
point for discussion before we start sorting through the details.

Randy,

Sorry for the lateness, I've not been as active as I had anticipated this
interval. But I should have more time next interval :/

AI glued below. [Editor's note: this was version /01 of the AI.]
Enjoy, and see you all in Vienna!

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

From: Randy Brukardt
Sent: Monday, June 12, 2017  6:02 PM

A couple of barely-informed thoughts on this one, too. (I read each of these as
I file it, thus some quick thoughts on each.)

...
> Enjoy, and see you all in Vienna!

Yes, and we can discuss the details some more there.

First of all, the basic idea seems sound. Having a couple of aspects to control
how such aggregates get constructed seems pretty sensible.

...

> Instead of "if" we could use "|" to mimic common mathematical
> notation, but it is probaby not a good idea to introduce the vertical
> bar into Ada at this point?

The vertical bar has been used in Ada to compose choice lists from the beginning
of time. It would be awful to try to use it for something else in the same
construct (that is, an aggregate). Since a "for" is just a kind of choice
(recall that we already added that in Ada 202x, see AI12-0061-1), which can be
used along with other forms of choices, using "|" in the syntax of some other
kind of choice would be confusing.

...
> Related changes:
>
> This AI will have some interesting interplay with let expressions and
> generators.
>
> This AI will (trivially) conflict with AI12-0127-1 (partial
> aggregates) as both add a new section to 4.3 and modify the syntax for
> 4.3.

It clearly interacts with AI12-0061-1 somewhat, as that also defines a "for"
syntax for aggregates. Probably no actual overlapping rules, but the two
syntaxes need to "feel" the same.

...
> The evaluation of a display_aggregate or comprehension_aggregate
> starts by creating a new object, evaluating the Empty function of the
> Comprehension aspect and assigning its result to the new object.
>
> For a unary_display the unary inclusion procedure is called for each
> expression in order, for a binary_display the binary inclusion
> procedure is called for each pair described by the binary_association.
...

I don't much like the name "unary_display": I'm reading a "display", my compiler
uses "displays" to implement up-level access to local variables, and I really
don't see any point in introducing yet another use of the term. We're talking
about container aggregates, why not call them that??

Re: "in order". Components in an Ada aggregate generally are evaluated in an
arbitrary order. I think we need to have a really good reason to go away from
that. So either you need to explain why the unusual rules or adjust this to be
in an arbitrary order. (Note that the new "for" construct executes in an
arbitrary order.)

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

From: Florian Schanda
Sent: Tuesday, June 13, 2017  1:43 AM

> I don't much like the name "unary_display": I'm reading a "display",
> my compiler uses "displays" to implement up-level access to local
> variables, and I really don't see any point in introducing yet another use
> of the term.
> We're talking about container aggregates, why not call them that??

I think calling display container aggregate would be fine. But we should stick
with the term "comprehension" for the, well, comprehensions.

> Re: "in order". Components in an Ada aggregate generally are evaluated
> in an arbitrary order. I think we need to have a really good reason to
> go away from that. So either you need to explain why the unusual rules
> or adjust this to be in an arbitrary order. (Note that the new "for"
> construct executes in an arbitrary order.)

We soon have precedence for this: the delta aggregates are also evaluated LTR.
Plus, if you think about it; an aggregate for a list where the elements are
added in arbitrary order would be a bit counter-intuitive.

Or maybe I am missing a finer point here, and you mean we evaluate in
arbitrary order, but still add LTR?

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

From: Randy Brukardt
Sent: Tuesday, June 13, 2017  1:06 PM

> > I don't much like the name "unary_display": I'm reading a "display",
> > my compiler uses "displays" to implement up-level access to local
> > variables, and I really don't see any point in introducing
> yet another use of the term.
> > We're talking about container aggregates, why not call them that??
>
> I think calling display container aggregate would be fine.
> But we should stick with the term "comprehension" for the, well,
> comprehensions.

WTF is a "comprehension"? I'd rather not stuff more obscure terminology into
Ada that is mostly going to get in the way of getting the job done.

> > Re: "in order". Components in an Ada aggregate generally are
> > evaluated in an arbitrary order. I think we need to have a really
> > good reason to go away from that. So either you need to explain why
> > the unusual rules or adjust this to be in an arbitrary order. (Note that
> > the new "for" construct executes in an arbitrary order.)
>
> We soon have precedence for this: the delta aggregates are also
> evaluated LTR.
> Plus, if you think about it; an aggregate for a list where the
> elements are added in arbitrary order would be a bit
> counter-intuitive.
>
> Or maybe I am missing a finer point here, and you mean we evaluate in
> arbitrary order, but still add LTR?

Well, I was actually thinking about maps, in which the order of insertion
should be irrelevant.

But you're right in that a list or vector aggregate is closest to an array
aggregate, and for that the order matters (if it is positional). But even
there, the order of evaluation is unspecified.

For maps/sets, the order of insertiong should be irrelevant. Same with a
named vector (do you have that? You ought to).

I didn't see what you proposed for a map, but IMHO I think it ought to look
something like:

   ("Tuck" => US, "Jeff" => UK, "Tuillo" => Italy, ...)

One easily can imagine a vector that works similarly, using the indexes:

   (1 => "Tuck", 2 => "Jeff", 3 => "Randy", 4 => "Florian", ...)

After all, Ada programmers learn that positional anything is bad at an early
stage; we don't want to force the use of positional aggregates unless there
is no other choice. (Yes, for a list, it seems that there is no sane way to
name the nodes, so positional is the only possibility.)

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

From: Florian Schanda
Sent: Wednesday, June 14, 2017  2:29 AM

> WTF is a "comprehension"? I'd rather not stuff more obscure
> terminology into Ada that is mostly going to get in the way of getting the
> job done.

It's a reasonable common construct in functional programming, but also
features in some imperatives languages. Here is an overview from wikipedia:

https://en.wikipedia.org/wiki/Comparison_of_programming_languages_%28list_comprehension%29

But I think the language that made the term popular was Python:

https://docs.python.org/2/reference/expressions.html#list-displays

They also distinguish between displays and comprehension; in Python a list can
be written as [1, 2, 3] which most people think of as a literal, but it is
actually a display.

Again, I hesitate to mention Python as my main inspiration for this because,
well, Python has many flaws, but I think this is one of the more elegant parts
of the language and I think our proposed approach to make this syntax work for
user-defined types and not just built-in types really sets it apart from other
languages.

> For maps/sets, the order of insertiong should be irrelevant. Same with
> a named vector (do you have that? You ought to).

Yes; all that matters is which "inclusion" function you specify (I've done it
for all the standard containers), for sets it is include (so (1, 2, 2, 3)
will do the obvious), for maps it is insert (since 1 => 2, 1 => 3 makes little
sense) and for lists it is append.

> I didn't see what you proposed for a map, but IMHO I think it ought to
> look something like:
>
>    ("Tuck" => US, "Jeff" => UK, "Tuillo" => Italy, ...)

Yes, that is what I have. I've called these binary because the inclusion
function has two parameters (in addition to the container) instead of just one.

> One easily can imagine a vector that works similarly, using the indexes:
>
>    (1 => "Tuck", 2 => "Jeff", 3 => "Randy", 4 => "Florian", ...)

We could do that, but it seems painful, so I'd rather not come up with grammar
that allows it. It would also mean the compiler would have to sort the list
first and that also seems like unnecessary complexity ;)

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

From: Tucker Taft
Sent: Wednesday, June 14, 2017  3:42 AM

> WTF is a "comprehension"? I'd rather not stuff more obscure terminology into
> Ada that is mostly going to get in the way of getting the job done.

A “set comprehension” is a well defined term in set theory.  E.g.:

   https://en.wikipedia.org/wiki/Set-builder_notation

Other sorts of "comprehensions" are generalizations of this notion.  But I
agree we don’t need to introduce this term into Ada.  We have already added
something that is essentially an "array comprehension" and we called it an
"iterated_component_association."  I don’t love that term either, but we
should probably stick with it.  I also find “display” a particularly
ambiguous term, and see no reason to use it here.

For what it is worth, I will send as a separate e-mail the ParaSail
description of user-defined container aggregates (as a PDF).  Not sure what
Randy’s e-mail system is going to do with that.

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

From: Tucker Taft
Sent: Wednesday, June 14, 2017  3:45 AM

Here it is.  Actually, this is for “Sparkel,” the SPARK-like variant of
araSail.

[Sorry, there is no way to attach that here. - Editor.]

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

From: Jeff Cousins
Sent: Wednesday, June 14, 2017  4:00 AM

> WTF is a "comprehension"?

Glad you said that before I did!

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

From: Randy Brukardt
Sent: Wednesday, June 14, 2017  2:26 PM

>They also distinguish between displays and comprehension; in Python a list can
>be written as [1, 2, 3] which most people think of as a literal, but it is
>actually a display.

I don't see the point in differentiation: in Ada, an aggregate is often though
of as a literal, but it can contain many dynamically determined parts, so there
really is no analogue in other languages.

And it is really is a small step from:

    (For I in Func1 .. Func2 => Func3(I))

which is just an Ada 202x array aggregate, and your proposed:

    (For E of Cont1 => Func(E))

No reason that I can see to differentiate them; your "displays" and
"comphrehensions" would have the exact same implementation outside of the
looping mechanism (and us implementers are used to that vis-a-vis aggregates).

>> One easily can imagine a vector that works similarly, using the indexes:
>>
>>    (1 => "Tuck", 2 => "Jeff", 3 => "Randy", 4 => "Florian", ...)
>
>We could do that, but it seems painful, so I'd rather not come up with grammar
>that allows it. It would also mean the compiler would have to sort the list
>first and that also seems like unnecessary complexity ;)

???

The grammar is that of an array aggregate, supplemented with your "for E of
whatever" syntax. No reason to do anything else. The semantics are different,
of course, but as little as necessary.

There's no requirement to "sort" the aggregate; the implementation would use
Insert to implement them, in any order it wants. It shouldn't matter (I guess
it would have to be a new Insert analog that expands the capacity as needed)
what order is used, as we're inserting by index. The implementation *could*
sort the aggregate so the capacity is allocated all at once, but it doesn't
have to do that optimization. Indeed, your original proposal would *require*
worst-case insertion behavior (where the capacity is increased multiple times,
the minimum amount each time, until it is big enough - yuck).

Anyway, to be discussed.

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

From: Tucker Taft
Sent: Thursday, June 22, 2017  11:19 AM

> >They also distinguish between displays and comprehension; in Python a
> >list can be written as [1, 2, 3] which most people think of as a
> >literal, but it is actually a display.
>
> I don't see the point in differentiation: in Ada, an aggregate is often
> though of as a literal, but it can contain many dynamically determined
> parts, so there really is no analogue in other languages.
>
> And it is really is a small step from:
>     (For I in Func1 .. Func2 => Func3(I)) which is just an Ada 202x
> array aggregate, and your proposed:
>     (For E of Cont1 => Func(E))
> No reason that I can see to differentiate them; your "displays" and
> "comphrehensions" would have the exact same implementation outside of the
> looping mechanism (and us implementers are used to that vis-a-vis aggregates). ...

I agree, we should use named and positional array aggregate syntax (and
vocabulary) for these new container aggregates, unless there is a compelling
reason to invent something new.

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

From: Tucker Taft
Sent: Friday, January 19, 2018  1:28 PM

I offered to take this one over from Florian, because he seems to be swamped
with other work, and I think this one is very important.  Essentially a
complete re-write, using terms "positional" and "named" container aggregates.
Also, introducing terms "element type" and "key type."  Hopefully it is
understandable.

[This is version /02 of the AI - ED.]
Comments welcome!

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

From: Edmond Schonberg
Sent: Friday, January 19, 2018   1:48 PM

Looks great, a much-needed addition to the language!

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

From: Randy Brukardt
Sent: Wednesday, January 24, 2018  11:29 PM

> Essentially a complete re-write, using terms "positional" and "named"
> container aggregates.

A few comments:

Are you using some funny editor/machine to create these attachments? They
look normal when opened in Notepad, but when I try to cut-and-paste pieces
(say into an e-mail message), the text comes out all on one line jammed
together. Linux files don't even work in Notepad (are just one long line),
so with those I know they need correction right away.

At least reading them with an Ada program and writing them out again
(Get_Line/Put_Line) makes a usable version.

---

There's some references in the proposal section to things that aren't going to
be in *this* AI ("concurrent aggregates"), and "related changes" seems
speculative at best. I'd just delete all of that.

---

> Given a private type or private extension T, the following
> type-related operational aspect may be specified:
>
>  Aggregate
>    This aspect is of the form:
>
>      (Empty => name[,
>       Add_Positional => /procedure_/name][,
>       Add_Named => /procedure_/name])
>
>    Either Add_Positional, Add_Named, or both shall be specified.

It took me a long time to figure out that there isn't a need for special syntax
here. I eventually realized that you are using a clever: this has the syntax of
an aggregate, so this aspect is being specified by an expression.

But this is a massive hack (and doesn't fit the rules given in 13.1.1,
specifically 13.1.1(7/3) and 13.1.1(21/3)): this "expression" has no definable
type, could never resolve by conventional means, can't be "evaluated to a
single value", doesn't match freezing rules, and probably more. I suppose your
intent is that this would have to be implemented with aspect-specific code
anyway, so it isn't a hardship to take an uninterpreted tree (required by
aspects anyway) and apply a custom interpretation to it.

However, if we're going to use a clever hack here, we have to define it properly
(with rule changes in 13.1.1). Also, we ought to do the same for other aspects.
In particular, the Stable_Properties aspects (for which I defined new syntax to
support lists of names, and which we already approved) probably should be
defined as a typeless positional array aggregate. Also, the Default_Iterator
and Iterator_Element probably should have a combined version (easier to use and
test).

Alternatively, we should simply (?) define a set of three interrelated aspects,
as we did for those other existing aspects. I suspect the amount of work for
this expression hack would be as much or more as defined three aspects. (At a
minimum, one would need several pages of code just to check that the arbitrary
expression that you are given actually is an aggregate, with 2 or 3 choices,
that each of those choices is a name, that each of those choices is in named
notation, that the names are the right ones... That would be extra code, not
needed for separate aspects, probably much bigger than the checks that
the Empty_Aggregate aspect was defined for the others.)

---

>If both Add_Positional and Add_Named are specified, the final
>parameters shall be of the same type -- the element type of T.

This rule is given under Name Resolution Rules, but this is clearly a Legality
Rule -- we never want to make resolution too smart. It should be moved.

---

> The expected type for a container_aggregate shall be a 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.

I don't think this works. All type aspects are independent of view
(see 13.1.1(27/3)). As such, it also applies to the full view, and as such the
common case of a full record type would define both record and container
aggregates.

I suppose we could use the "unless otherwise specified" exception, but I don't
want to start making exceptions to type aspects, that opens a Pandora's box of
anomalies. Besides, we don't (well, at least *I* don't) want container
aggregates to disappear for full types that don't have aggregates of their
own. It's just the conflict cases that need solution.

[Aside: I think this is probably the right solution for prefixed names as
well; allow the prefixed names to be used on operations that can see the full
type, but only if they are defined for the private type, and only with the
semantics of the private type -- thus a private type completed with an access
type would allow prefixed calls, but a dereference of the access type would
not be considered as a possible prefix. A bit wonky, perhaps, but worlds
better than prefixed notation disappearing when a declaration is moved a few
lines after the full type.]

Anyway, I suggest that any type with a conflict be resolved in terms of using
the built-in aggregates rather than the aspect. Perhaps:

    The expected type for a container_aggregate shall be a type for which
    the Aggregate aspect has been specified and which is not an array or record
    type.

---

>  * for a named_container_aggregate for a type with an Add_Named procedure
>    in its Aggregate aspect, the container_element_associations are evaluated
>    in any order:

I think the wording is "an unspecified order". It's this wording that triggers
the anti-order-dependence checks of 6.4.1. There are several more of these.

---

>Examples
>
>I KNOW I NEED TO REWORK THESE TO USE EXISTING THINGS IN THE RM

That's been in the AI for a while now, when is this happening?

---

>   --  Is (mostly, assuming set semantics) equivalent to
>   S := (for Item in -5 .. 5 when Item /= 0 => Item);

There are several examples using "when" in here; those should be removed from
this AI which doesn't include "when" in the syntax.

---

There aren't any examples of named aggregates, I was trying to figure out the
usage of the key_expression in an iterator and didn't find any.

---

>A.18.2 The Generic Package Containers.Vectors
>
>Add the Aggregate aspect to the existing ones on type Vector:
>
>   type Vector is tagged private
>      with Constant_Indexing => Constant_Reference,
>           Variable_Indexing => Reference,
>           Default_Iterator  => Iterate,
>           Iterator_Element  => Element_Type,
>           Aggregate         => (Empty          => Empty_Vector,
>                                 Add_Positional => Append);

It might not be worth the effort, but it seems annoying that one cannot write
named array aggregates for Vectors. After all, the idea is to make these as
close to arrays as we can. It is especially annoying that one can't write an
iterator for these:

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

to initialize a Vector with the values 1 through 10. (Since we just finally
fixed this problem for regular array aggregates.)

One possibility would be to define an Add_Named for this purpose, although
we'd need a new length-expanding Insert operation for the purpose (since the
order isn't defined). With that change, named aggregates could be written, but
without ranges (other than in iterators), and without a check for missing
elements (which seems like a bridge too far for this aspect in any case).

---

And that's all I've got. The basic ideas seem sound. And it is much more
pleasant that the original version, having lost all of the terminology and
feature gee-gaws that were jammed into the original proposal (and of which
some vestiges remain).

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

From: Tucker Taft
Sent: Thursday, January 25, 2018  3:51 AM

>> Essentially a complete re-write, using terms "positional" and "named"
>> container aggregates.
>
> A few comments:
>
> Are you using some funny editor/machine to create these attachments?
> They look normal when opened in Notepad, but when I try to
> cut-and-paste pieces (say into an e-mail message), the text comes out
> all on one line jammed together. Linux files don't even work in
> Notepad (are just one long line), so with those I know they need correction right away.
>
> At least reading them with an Ada program and writing them out again
> (Get_Line/Put_Line) makes a usable version.

Nothing special in the way of an editing tool (TextWrangler typically, or
vi/vim), though I might have neglected to add newlines in this one.  Usually I
try to keep the lines short, but the editor automatically wraps when displaying,
so sometimes I leave in some very long lines.

> ---
>
> There's some references in the proposal section to things that aren't
> going to be in *this* AI ("concurrent aggregates"), and "related
> changes" seems speculative at best. I'd just delete all of that.

I didn't want to delete any of Florian's original examples.  Feel free.

> ---
>
>> Given a private type or private extension T, the following
>> type-related operational aspect may be specified:
>>
>> Aggregate
>>   This aspect is of the form:
>>
>>     (Empty => name[,
>>      Add_Positional => /procedure_/name][,
>>      Add_Named => /procedure_/name])
>>
>>   Either Add_Positional, Add_Named, or both shall be specified.
>
> It took me a long time to figure out that there isn't a need for
> special syntax here. I eventually realized that you are using a
> clever: this has the syntax of an aggregate, so this aspect is being specified
> by an expression.

I agree we probably need more syntax here.  The Global annotation uses similar
kinds of aggregate-like syntax, and I think it is better to keep these things
together in a single "aggregate-like" syntax.

> But this is a massive hack (and doesn't fit the rules given in 13.1.1,
> specifically 13.1.1(7/3) and 13.1.1(21/3)): this "expression" has no
> definable type, could never resolve by conventional means, can't be
> "evaluated to a single value", doesn't match freezing rules, and
> probably more. I suppose your intent is that this would have to be
> implemented with aspect-specific code anyway, so it isn't a hardship
> to take an uninterpreted tree (required by aspects anyway) and apply a custom interpretation to it.
>
> However, if we're going to use a clever hack here, we have to define
> it properly (with rule changes in 13.1.1). Also, we ought to do the
> same for other aspects. In particular, the Stable_Properties aspects
> (for which I defined new syntax to support lists of names, and which
> we already approved) probably should be defined as a typeless
> positional array aggregate. Also, the Default_Iterator and
> Iterator_Element probably should have a combined version (easier to use and
> test).
>
> Alternatively, we should simply (?) define a set of three interrelated
> aspects, as we did for those other existing aspects.

I don't like having a set of separate aspects that are implicitly tied together
like that.  Convention, Import, and Export were probably a mistake.

> I suspect the amount of
> work for this expression hack would be as much or more as defined
> three aspects. (At a minimum, one would need several pages of code
> just to check that the arbitrary expression that you are given
> actually is an aggregate, with 2 or 3 choices, that each of those
> choices is a name, that each of those choices is in named notation, that
> the names are the right ones...
> That would be extra code, not needed for separate aspects, probably
> much bigger than the checks that Empty_Aggregate aspect was defined
> for the
> others.)

I do not think we should be worried about the parsing expense here.  Almost
every complex pragma has special parsing rules, and we seem to have survived
that.

> ---
>
>> If both Add_Positional and Add_Named are specified, the final
>> parameters shall be of the same type -- the element type of T.
>
> This rule is given under Name Resolution Rules, but this is clearly a
> Legality Rule -- we never want to make resolution too smart.

Yes, I suppose this rule shouldn't be used to help resolve the procedures --
that would be a whole new kind of overload resolution.

> ---
>
>> The expected type for a container_aggregate shall be a 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.
>
> ...

> Anyway, I suggest that any type with a conflict be resolved in terms
> of using the built-in aggregates rather than the aspect.
> Perhaps:
>
>    The expected type for a container_aggregate shall be a type for which
>    the Aggregate aspect has been specified and which is not an array
> or record type.

I think we should be more explicit here if we want to try to make this
distinction, and indicate that the expected type cannot be the full view of an
array or record type, but it can be the partial view of such a type.

> ---
>
>> * for a named_container_aggregate for a type with an Add_Named procedure
>>   in its Aggregate aspect, the container_element_associations are evaluated
>>   in any order:
>
> I think the wording is "an unspecified order". It's this wording that
> triggers the anti-order-dependence checks of 6.4.1. There are several
> more of these.

Actually, I believe the more frequent phraseology is "in an arbitrary order"
(e.g. see 5.2(7), 6.4(10), 6.4.1(17), etc.).

> ---
>
>> Examples
>>
>> I KNOW I NEED TO REWORK THESE TO USE EXISTING THINGS IN THE RM
>
> That's been in the AI for a while now, when is this happening?

I don't think reviewing examples at that level of detail is the kind of thing we
are going to be doing in a phone call.  Remember this was a complete re-write.
My priorities were to focus on the part that might be reviewed in the 29-Jan
call.

 ---
>
>>  --  Is (mostly, assuming set semantics) equivalent to  S := (for
>> Item in -5 .. 5 when Item /= 0 => Item);
>
> There are several examples using "when" in here; those should be
> removed from this AI which doesn't include "when" in the syntax.

I had intended those to have an appropriate comment that the "when" syntax would
be discussed in a separate AI.

> ---
>
> There aren't any examples of named aggregates, I was trying to figure
> out the usage of the key_expression in an iterator and didn't find any.

Good point.  Here is a simple one where you have a table of keys and values, and you want to create a mapping built from that table:

   Map : constant Mapping := (for I in Table'Range, Table(I).Key => Table(I).Value);


>
> ---
>
>> A.18.2 The Generic Package Containers.Vectors
>>
>> Add the Aggregate aspect to the existing ones on type Vector:
>>
>>  type Vector is tagged private
>>     with Constant_Indexing => Constant_Reference,
>>          Variable_Indexing => Reference,
>>          Default_Iterator  => Iterate,
>>          Iterator_Element  => Element_Type,
>>          Aggregate         => (Empty          => Empty_Vector,
>>                                Add_Positional => Append);
>
> It might not be worth the effort, but it seems annoying that one
> cannot write named array aggregates for Vectors. After all, the idea
> is to make these as close to arrays as we can. It is especially
> annoying that one can't write an iterator for these:
>
>      (for I in 1..10 => I)
>
> to initialize a Vector with the values 1 through 10. (Since we just
> finally fixed this problem for regular array aggregates.)

This is allowed.  You can use named notation even if there is no Add_Named.  An
iterated component association just turns into a sequence of calls on
Add_Positional.  I think that is pretty important.

> One possibility would be to define an Add_Named for this purpose,
> although we'd need a new length-expanding Insert operation for the
> purpose (since the order isn't defined). With that change, named
> aggregates could be written, but without ranges (other than in
> iterators), and without a check for missing elements (which seems like
> a bridge too far for this aspect in any case).

I thought about that, but it seems kludgey.  I prefer just allowing the use of
Add_Positional as illustrated above.  Perhaps the wording needs to be clarified
that, in the absence of Add_Named, you can still use iterated component
associations, so long as there are no key_expressions.  Here are some extracts
from the AI that permit the use of Add_Positional for a named array aggregate,
so long as it has no key_expressions:

   "... The expected type for a named_container_aggregate that has one or more
     /key_/expressions shall have an Aggregate aspect that includes a
     specification for the Add_Named procedure. ..."

  " ...  for a named_container_aggregate for a type without an Add_Named
     procedure in its Aggregate aspect, the container_element_associations
     (which are necessarily iterated_element_associations)
     are evaluated in the order given: ..."

Perhaps the "intro" paragraph is the place to mention this possibility more
explicitly.

> ---
>
> And that's all I've got. The basic ideas seem sound. And it is much
> more pleasant that the original version, having lost all of the
> terminology and feature gee-gaws that were jammed into the original
> proposal (and of which some vestiges remain).

OK, glad to hear that it looks better to you.

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

From: Randy Brukardt
Sent: Thursday, January 25, 2018  5:08 PM

> > At least reading them with an Ada program and writing them out again
> > (Get_Line/Put_Line) makes a usable version.
>
> Nothing special in the way of an editing tool (TextWrangler typically,
> or vi/vim), though I might have neglected to add newlines in this one.
> Usually I try to keep the lines short, but the editor automatically
> wraps when displaying, so sometimes I leave in some very long lines.

Yes, that's a problem, too, but I'm used to that.

Opening one of these files in an ancient MS-DOS editor shows lots of little
musical note characters sprinkled about. I think those are unpaired <CR>s (or
unpaired <LF>s? I can't find a character chart). I suppose I could trying
looking in a hex editor...

> >
> > ---
> >
> > There's some references in the proposal section to things that
> > aren't going to be in *this* AI ("concurrent aggregates"), and
> > "related changes" seems speculative at best. I'd just delete all of that.
>
> I didn't want to delete any of Florian's original examples.
> Feel free.

It's in the !proposal, not the !problem. Talking about proposals not made is
just confusing.

> >> Given a private type or private extension T, the following
> >> type-related operational aspect may be specified:
> >>
> >> Aggregate
> >>   This aspect is of the form:
> >>
> >>     (Empty => name[,
> >>      Add_Positional => /procedure_/name][,
> >>      Add_Named => /procedure_/name])
> >>
> >>   Either Add_Positional, Add_Named, or both shall be specified.
> >
> > It took me a long time to figure out that there isn't a need for
> > special syntax here. I eventually realized that you are using a
> > clever: this has the syntax of an aggregate, so this aspect
> is being specified by an expression.
>
> I agree we probably need more syntax here.  The Global annotation uses
> similar kinds of aggregate-like syntax, and I think it is better to
> keep these things together in a single "aggregate-like" syntax.

OK. It may make sense to try to define that separately (so that multiple aspects
can use it). But in any case, it shouldn't appear here without either a
definition or a cross-reference to a different AI.

...
> > Alternatively, we should simply (?) define a set of three
> > interrelated aspects, as we did for those other existing aspects.
>
> I don't like having a set of separate aspects that are implicitly tied
> together like that.  Convention, Import, and Export were probably a
> mistake.

Didn't think of those. These are more like Default_Iterator and Iterator_Type
(one has to be specified before the other, as I recall). That says that there
are at least three sets like that.

> > I suspect the amount of
> > work for this expression hack would be as much or more as defined
> > three aspects. (At a minimum, one would need several pages of code
> > just to check that the arbitrary expression that you are given
> > actually is an aggregate, with 2 or 3 choices, that each of those
> > choices is a name, that each of those choices is in named notation,
> > that the names are the right ones...
> > That would be extra code, not needed for separate aspects, probably
> > much bigger than the checks that Empty_Aggregate aspect was defined
> > for the
> > others.)
>
> I do not think we should be worried about the parsing expense here.
> Almost every complex pragma has special parsing rules, and we seem to
> have survived that.

I wasn't thinking about "parsing expense", I was thinking about "legality check
expense". If one uses the syntax of an expression, then it will be parsed as an
expression, and then that has to be checked piece-by-piece for correctness.

And, as always, two wrongs don't make a right. Some of the pragmas are hard to
get right and take a lot of one-time use code (so it doesn't get tested much.
This is one of the reasons I am so happy to get rid of pragmas!

...
> > ---
> >
> >> The expected type for a container_aggregate shall be a 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.
> >
> > ...
>
> > Anyway, I suggest that any type with a conflict be resolved
> in terms
> > of using the built-in aggregates rather than the aspect.
> > Perhaps:
> >
> >    The expected type for a container_aggregate shall be a type for which
> >    the Aggregate aspect has been specified and which is not an array
> >    or record type.
>
> I think we should be more explicit here if we want to try to make this
> distinction, and indicate that the expected type cannot be the full
> view of an array or record type, but it can be the partial view of
> such a type.

Fair enough. I'm sure you'll propose some wording.

> > ---
> >
> >> * for a named_container_aggregate for a type with an Add_Named procedure
> >>   in its Aggregate aspect, the container_element_associations are evaluated
> >>   in any order:
> >
> > I think the wording is "an unspecified order". It's this wording
> > that triggers the anti-order-dependence checks of 6.4.1. There are
> > several more of these.
>
> Actually, I believe the more frequent phraseology is "in an arbitrary
> order" (e.g. see 5.2(7), 6.4(10), 6.4.1(17), etc.).

You're right. In any case, "any order" is not the proper wording. (I suppose you
inherited that.)

> > ---
> >
> >> Examples
> >>
> >> I KNOW I NEED TO REWORK THESE TO USE EXISTING THINGS IN THE RM
> >
> > That's been in the AI for a while now, when is this happening?
>
> I don't think reviewing examples at that level of detail is the kind
> of thing we are going to be doing in a phone call.
> Remember this was a complete re-write.  My priorities were to focus on
> the part that might be reviewed in the 29-Jan call.

Well, these calls are normal ARG meetings, so anything that we would do in a
normal meeting is fair game. In particular, we can approve AIs -- but we can't
do that until the examples are right.

I agree this probably isn't ready for approval yet, but it might be next time,
and this note was really about stuff to put into your next rewrite. (I'm only
asking for one rewrite per meeting; more are OK, but I don't want to be
unreasonable.)

> >
> > ---
> >
> >>  --  Is (mostly, assuming set semantics) equivalent to  S := (for
> >> Item in -5 .. 5 when Item /= 0 => Item);
> >
> > There are several examples using "when" in here; those should be
> > removed from this AI which doesn't include "when" in the syntax.
>
> I had intended those to have an appropriate comment that the "when"
> syntax would be discussed in a separate AI.

I suppose that would work, assuming of course that that AI goes anywhere.

> > ---
> >
> > There aren't any examples of named aggregates, I was trying to
> > figure out the usage of the key_expression in an iterator and didn't find
> > any.
>
> Good point.  Here is a simple one where you have a table of keys and
> values, and you want to create a mapping built from that table:
>
>    Map : constant Mapping := (for I in Table'Range, Table(I).Key =>
> Table(I).Value);

Thanks. Put that into the next draft. ;-)

> > ---
> >
> >> A.18.2 The Generic Package Containers.Vectors
> >>
> >> Add the Aggregate aspect to the existing ones on type Vector:
> >>
> >>  type Vector is tagged private
> >>     with Constant_Indexing => Constant_Reference,
> >>          Variable_Indexing => Reference,
> >>          Default_Iterator  => Iterate,
> >>          Iterator_Element  => Element_Type,
> >>          Aggregate         => (Empty          => Empty_Vector,
> >>                                Add_Positional => Append);
> >
> > It might not be worth the effort, but it seems annoying that one
> > cannot write named array aggregates for Vectors. After all, the idea
> > is to make these as close to arrays as we can. It is especially
> > annoying that one can't write an iterator for these:
> >
> >      (for I in 1..10 => I)
> >
> > to initialize a Vector with the values 1 through 10. (Since we just
> > finally fixed this problem for regular array aggregates.)
>
> This is allowed.  You can use named notation even if there is no
> Add_Named.  An iterated component association just turns into a
> sequence of calls on Add_Positional.  I think that is pretty
> important.

OK, but I also might want to write:

    Is_Odd : Bool_Vector := (1 | 3 | 5 | 7 | 9 => True, 0 | 2 | 4 | 6 | 8 => False);

Again, the goal is to get a Vector aggregate to be as close to an array
aggregate as possible.

Also, this seems to give a preverse incentive to use iterators because other
forms of name aren't allowed:

    Is_Prime : Bool_Vector := (for I in 1..1 => False, for I in 2..3 => True,
                               for I in 4..4 => False, for I in 5..5 => True);

You *know* people are going to write this, because you're not allowing them to
write what they want.

> > One possibility would be to define an Add_Named for this purpose,
> > although we'd need a new length-expanding Insert operation for the
> > purpose (since the order isn't defined). With that change, named
> > aggregates could be written, but without ranges (other than in
> > iterators), and without a check for missing elements (which seems
> > like a bridge too far for this aspect in any case).
>
> I thought about that, but it seems kludgey.  I prefer just allowing
> the use of Add_Positional as illustrated above.
> Perhaps the wording needs to be clarified that, in the absence of
> Add_Named, you can still use iterated component associations, so long
> as there are no key_expressions.

Honestly, that seems like much more of a kludge to me. The existence of "=>" is
what changes an aggregate from positional to named, and I'd hate to lose that
property. (I know there's a hack allowing "others =>" in positional aggregates,
but that also feels wrong. Again, two wrongs don't make a right.) Morevoer, the
use of indexes as keys seems natural (what else are they if not a predefined
kind of key)?

Now, a real kludge here would be to give "keys" of discrete types special
properties, specifically that
    A .. B => ...
is equivalent to
    for I in A .. B => ...
if the key type is discrete.

Then a named vector aggregate could look just like a named array aggregate (sans
"others", which can't make sense in this context, as there is nowhere to get a
Length from). To make the equivalence close to perfect, we'd need a way to make
a completeness check, but that seems hard and somewhat unnecessary.

> ...

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

From: Raphaël Amiard
Sent: Friday, January 26, 2018  8:46 AM

So I said I would report on C++ facilities for creating container literals.

After some studying it turns out that it is not really relevant:

1. C++ lacks something akin to the aggregate syntax. All they have are
   initializer lists, which are much more primitive and crude.

2. Their system extensively uses C++ templates, and their implicit
   instantiation ability. So it is not a good basis for us.

3. Our proposal is more advanced in terms of features already.

That's it !

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


Questions? Ask the ACAA Technical Agent