!standard 5.5(6.2/6) 19-04-08 AI12-0327-1/02 !standard 4.3.3(20.4/5) !standard 4.3.5(0) !standard 4.5.8(6/4) !standard 4.5.10(0) !class Amendment 19-04-05 !status work item 19-04-05 !status received 19-03-18 !priority Low !difficulty Easy !subject Clarify iterator filter wording for aggregates !summary The Iterator filter wording for aggregates and quantified expressions is made more explicit. !problem The wording in 5.5 that discusses how loop_parameter_specification and iterator_specification work in contexts other than loop_statements never describes how the values assigned to the loop parameter turn into values "produced by" the iterator. In addition, none of the wording in the uses of these iterators (in aggregates, reductions, and quantified expressions) ever makes it clear that the filter plays a role. We need wording that explains what it actually happening, rather than wording that leaves everything to the imagination of the reader. !proposal (See Summary.) !wording [The paragraph numbers in this AI are for draft 19 of the RM - Editor.] Replace 5.5(6.2/5) with: The /filter/ of an /iterator construct/ (a loop_parameter_specification, iterator_specification, or procedural_iterator) is defined to be /satisfied/ when there is no iterator_filter for the iterator construct, or when the condition of the iterator_filter evaluates to True for a given iteration of the loop iterator. When we say that the sequence_of_statements of a loop_statement is /conditionally executed/, the statements are executed only when the filter of the iterator construct is satisfied. [Author's note: This wording used to talk about "the term conditionally executed"; we never write definitions in terms of a meta-definition; we almost always just say what the term means.] The loop iterators loop_parameter_specification and iterator_specification can also be used in contexts other than loop_statements (for example, see 4.3.5 and 4.5.8). In such a context, the iterator *conditionally produces* values in the order specified for the associated construct below or in 5.5.2. The values produced are the values given to the loop parameter when the filter of the iterator construct is satisfied for that value. Redundant[No value is produced when the condition of an iterator_filter evaluates to False.] Modify 4.3.3(20.4/5): 2. A second iteration is performed for each of the iterator_specifications, in the order given in the aggregate, and for each value {conditionally} produced {by the iteration (see 5.5 and 5.5.2)}, the associated expression 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. Modify 4.3.5(47/5): * for a container_element_association with an iterated_element_association, first the iterated_element_association is elaborated, then an iteration is performed{, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2)}[ as described in 5.5 or 5.5.2, 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: Modify 4.3.5(53/5): 2. an iteration is performed{, and for each value conditionally produced by the iteration (see 5.5 and 5.5.2)}[ as described in 5.5 or 5.5.2, and for each value of the loop parameter of the iteration, ]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. Modify 4.5.8(6/4): For the evaluation of a quantified_expression, the loop_parameter_specification or iterator_specification is first elaborated. The evaluation of a quantified_expression then {performs an iteration, and }evaluates the predicate for {each value conditionally produced by the iteration (see 5.5 and 5.5.2)} [the values of the loop parameter in the order specified by the loop_parameter_specification (see 5.5) or iterator_specification (see 5.5.2)]. {AARM Ramification: The order of evaluation of the predicates is that in which the values are produced, as specified in 5.5 or 5.5.2.} Modify 4.5.10(27/5): For the evaluation of a value_sequence, the iterated_element_association is elaborated, then an iteration is performed[as described in 5.5 or 5.5.2], and for each value {conditionally} produced by the [iterator]{iteration (see 5.5 and 5.5.2)}, the associated expression is evaluated with the loop parameter having this value, to produce a result that is converted to Value_Type, and used to define the next value in the sequence. !discussion This wording makes where the values come from explicit. The 4.3.5 wording was OK in this respect (since it talked about the loop parameter), but the other wording was not. We make all of the wording consistent in order to ease future maintenance, even the 4.3.5 wording (since it did not clearly describe the role of the filter). !ASIS [Not sure. It seems like some new capabilities might be needed, but I didn't check - Editor.] !ACATS test ACATS B- and C-Tests are needed to check that the new capabilities are supported. !appendix From: Randy Brukardt Sent: Monday, March 18, 2019 9:12 PM I'm putting AI12-0250-1 into the draft RM, and as usual that means reading the wording more carefully than before. 4.3.3(20.4/5) is modified as follows: 2. A second iteration is performed for each of the iterator_specifications, in the order given in the aggregate, and for each value produced, the associated expression 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 [the same} {an} array length {no greater than the maximum determined by the first iteration}; Constraint_Error is raised if this check fails. Nothing in this wording implies that the part about evaluating the "associated expression" is conditional on the filter. One could apply the Dewar rule here (having a filter and ignoring it doesn't make sense), but that's horrible. Tucker added the following sentence to 5.5 to "fix" this problem: In contexts where a loop_parameter_specification or iterator_specification is used to produce a sequence of values (see 4.3.3 and 4.3.5), if an iterator_filter is present, the sequence of values will contain only the values for which the iterator_filter is satisfied. But this doesn't make a lot of sense: (1) As this is written, it doesn't appear to apply to 4.5.8 or 4.5.10. The rewording of 4.5.10 also uses the "for each value produced" wording, and it might arguably "produce a sequence of values", but the lack of a cross-reference means that one isn't sure. (It doesn't read like examples of places where this happens, it seems like a complete list.) For 4.5.8, the wording is "the predicate is evaluated for the values of the loop parameter in the order specified ..." - "produced" doesn't appear either. In none of these four places does the word "sequence" appear, so there is no strong tie to the places as to where this wording applies - it pretty much is whatever the reader wants it to be. (2) In the cases of the aggregates, the "sequence of values" of interest is that of the components of the array or elements of the container. It's not at all clear how one leaps from those to the (virtual) sequence of values created by the iterator. (3) The wording is very different from the loop statement case, where all of the values are generated and then the sequence_of_statements is conditionally executed. Given that the "sequence of values" is derived from that wording purely by hand waving (the wording for loop statements talks about the successive values of the loop parameter, how that somehow morphs into a "sequence of values" is never described anywhere), having the wording being presented differently just adds to the confusion. (4) There's no indication at the point of use (that is, in 4.3.3, 4.3.5, 4.5.8, and 4.5.10) that the values are anything other than those provided directly by the iterator. At a minimum, there ought to be some clear terminology that makes it clear that there is more going on than just providing the values in turn. (5) I'd rather avoid talking about "sequences of values" outside of reductions, since such an idea is more formally presented there and doing so elsewhere is going to be confusing (particularly when the semantics differs). -- OK, I've griped enough. I suppose I have to propose something (especially with Tucker on vacation). This is a hard problem, and I think we need to do more to describe where the values come from. (I've been griping about that for years -- since the introduction of quantified expressions -- without getting anything done.) So, rather than having a single sentence, I think we need a paragraph on this topic. So, perhaps delete the sentence noted above and create a new paragraph instead: The constructs loop_parameter_specification and iterator_specification can also be used in contexts other than loop_statements. Redundant[They can be used, for instance, in container aggregates (see 4.3.5) and quantified expressions (see 4.5.8).] In such a context, the iterator *conditionally produces* values in the order specified for the associated construct below or in 5.5.2. The values produced are the values given to the loop parameter when there is no iterator_filter or the iterator_filter evaluates to True. Redundant[No value is produced when the iterator_filter (if any) evaluates to False.] Then, we would change each of the places involved to clearly use the wording "conditionally produced" with a cross-reference. Thus, in 4.3.3(20.4/5) above, we would make the following minor change: 2. A second iteration is performed for each of the iterator_specifications, in the order given in the aggregate, and for each value {conditionally} produced {by the iteration (see 5.5 and 5.5.2)}, the associated expression is evaluated, its value is converted to ... (I added both cross-references here rather than just 5.5 for the new term; the other locations already have references to 5.5.2 and it seems valuable everywhere.) We'd make similar (but somewhat larger) changes to 4.3.5(47/5), 4.3.5(53/5), 4.5.8(6/4), and 4.5.10(27/5). [Draft 18 numbering, these may be different in draft 19 because of the addition of AI12-0250-1 wording.] Assuming that there isn't a lot of pushback on this idea, I'll write something up for the next meeting. Thoughts? Improvements? Brickbats? **************************************************************** From: Randy Brukardt Sent: Monday, March 18, 2019 10:41 PM I probably should have used Tucker's "satisfied" wording in this paragraph, it's more specific about the evaluation of the iterator_filter. That would shorten it a touch to: The constructs loop_parameter_specification and iterator_specification can also be used in contexts other than loop_statements. Redundant[They can be used, for instance, in container aggregates (see 4.3.5) and quantified expressions (see 4.5.8).] In such a context, the iterator *conditionally produces* values in the order specified for the associated construct below or in 5.5.2. The values produced are the values given to the loop parameter when there is no iterator_filter or the iterator_filter is satisfied. Redundant[No value is produced when the iterator_filter is not satisfied.] [Aside: I'm not sure why Tucker didn't simply define "satisfied" in such a way that if there is no filter, it is satisfied. That would reduce the wording further, both here and in the loop_statement case. I suppose it is because of the oddity of talking about syntax that isn't there. But we could get around that by talking about the "filter" of an iterator. Something like: The /filter/ of an /iterator construct/ (a loop_parameter_specification, iterator_specification, or procedural_iterator) is defined to be /satisfied/ when there is no iterator_filter for the iterator construct, or when the condition of the iterator_filter evaluates to True for a given iteration of the loop iterator. Then: The term /conditionally executed/ when referring to the sequence_of_statements of a loop_statement means that the statements are executed only when the filter of the iterator construct is satisfied. And the above: The loop iterators loop_parameter_specification and iterator_specification can also be used in contexts other than loop_statements. Redundant[They can be used, for instance, in container aggregates (see 4.3.5) and quantified expressions see 4.5.8).] In such a context, the iterator *conditionally produces* values in the order specified for the associated construct below or in 5.5.2. The values produced are the values given to the loop parameter when the filter of the iterator construct is satisfied for that value. Redundant[No value is produced when the condition of an iterator_filter evaluated to False.] I'm not a fan of "iterator construct" as a term, but we need something shorter than "loop_parameter_specification, iterator_specification, or procedural_iterator" all over the place. I didn't want to just use "iterator", as that would seem to conflict with more specific terminology in 5.5.2. End Aside] ****************************************************************