!standard 3.3(23/3) 18-11-15 AI12-0294-1/01 !standard 5.5(8) !standard 5.5(9/5) !standard 5.5(9.1/5) !standard 5.5.3(20/5) !class Amendment 18-11-15 !status Amendment 1-2012 18-11-15 !status work item 18-11-15 !status received 18-10-21 !priority Low !difficulty Easy !subject More clean-ups for Ada 2020 !summary [Editor's note: These cleanups have already been applied to the draft Standard.] Various minor issues are corrected: (1) Accept statements are banned in the body of a procedural iterator loop. (2) Wording involving the nominal subtype of an object is improved. (3) The elaboration order of a chunk_specification and a loop_parameter_specification is that the chunk_specification is elaborated first. !problem Various minor issues, mostly caused by other Amendment AIs, are repaired. (1) 5.5.3 (from AI12-0189-1) allows accept statements in the body of a procedural iterator loop. However, such accept statements would be illegal if the loop was written manually (as 9.5.2(14) would be violated. (2) 3.3(23/3) contains the following sentence: "The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an indefinite subtype." The middle "is" in this sentence is hanging and it's unclear to what it refers. This should be clarified. (3) AI12-0251-1 proposes that a loop_parameter_specification is elaborated and parameters are created before the chunk_specification, if any, is elaborated. But the number of loop parameters to create is determined, in part, by the chunk_specification. Moreover, this is specifying an order different than the order in which these constructs are written. This is weird. !proposal (See Summary.) !wording (1) Add after 5.5.3(20/5) [from AI12-0189-1]: The sequence_of_statements of a loop_statement with a procedural_iterator as its iteration_scheme shall not contain an accept_statement. AARM Reason: An accept_statement is not allowed in a procedure (see 9.5.2), it has to be directly in a task_body. Since the loop body here is implemented as a procedure, we can't allow accept_statements there, either, even if the loop itself is directly in a task_body. AARM Ramification: This includes cases where the accept_statement is part of another construct, for instance, a select_statement. (2) Modify 3.3(23/3): The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is {more restrictive} if the nominal subtype is an indefinite subtype. (3) Replace 5.5(9/5-9.1/5): [As modified by AI12-0119-1 and AI12-0251-1] If the reserved word parallel is present in a loop_statement (a /parallel loop/), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9). If a chunk_specification is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the chunk_specification is an /integer_/simple_expression, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a discrete_subtype_definition is present, the elaboration elaborates the discrete_subtype_definition, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the chunk_specification, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. For the execution of a loop_statement that has an iteration_scheme including a loop_parameter_specification, after elaborating the chunk_specification, if any, the loop_parameter_specification is elaborated. This elaboration elaborates the discrete_subtype_definition, which defines the subtype of the loop parameter. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a /sequential loop/), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. If a chunk_specification with a discrete_subtype_definition is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. !discussion (1) As noted in the problem, 9.5.2(14) would make an accept statement illegal in a procedure, if the loop was written explicitly. Of course, that's true for exit and goto as well, and we require those to be implemented. But those terminate the iteration, while an accept statement would not have that effect. So supporting that would complicate the implementation for no obvious benefit. Therefore, we ban then unconditionally in this case. (2) This wording goes back to the 2.0 version of Ada 9x (that is, the first version with actual wording), so fixing it isn't a priority. However, the original question arose from an ARG member who though that "as" was missing from this text. The resulting sentence would violate the Dewar rule (surely not all nominal subtypes are indefinite). The author then spent a substantial amount of time trying to figure out a meaning that doesn't violate the Dewar rule. A normal reader shouldn't have to apply the Dewar rule to be able to read the RM, thus we clarify the sentence. No change in meaning is intended. (3) It appears that it was easier to fit chunk_specifications into the existing wording if they were elaborated later. But, as noted above, that causes ramifications that are problematical. While the creation of loop parameters doesn't have any detectable effect, it still seems strange to require doing something before there is enough information to decide the details of what to do. In reversing the elaboration, we also reversed the order of the paragraphs in the wording. This required substantial revisions to the wording, so that the definitions of "parallel loop" and "chunk" come before the usages. !corrigendum 3.3(23/3) @drepl At the place where a view of an object is defined, a @i is associated with the view. The object's @i (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an @i. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise, the subtype is a @i subtype (all elementary subtypes are definite subtypes). A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional @fa or explicit initialization @fa is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype. @dby At the place where a view of an object is defined, a @i is associated with the view. The object's @i (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is more restrictive if the nominal subtype is an @i. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise, the subtype is a @i subtype (all elementary subtypes are definite subtypes). A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional @fa or explicit initialization @fa is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype. !corrigendum 5.5(8) @dinsa For the execution of a @fa with a @b @fa, the @fa is evaluated before each execution of the @fa; if the value of the @fa is True, the @fa is executed; if False, the execution of the @fa is complete. @dinst If the reserved word @b is present in a @fa (a @i), the iterations are partitioned into one or more @i, each with its own separate logical thread of control (see clause 9). If a @fa is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the @fa is an @i@fa, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a @fa is present, the elaboration elaborates the @fa, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the @fa, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. !corrigendum 5.5(9/4) @drepl For the execution of a @fa with the @fa being @b @fa, the @fa is first elaborated. This elaboration creates the loop parameter and elaborates the @fa. If the @fa defines a subtype with a null range, the execution of the @fa is complete. Otherwise, the @fa is executed once for each value of the discrete subtype defined by the @fa that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. These values are assigned in increasing order unless the reserved word @b is present, in which case the values are assigned in decreasing order. @dby For the execution of a @fa that has an @fa including a @fa, after elaborating the @fa, if any, the @fa is elaborated. This elaboration elaborates the @fa, which defines the subtype of the loop parameter. If the @fa defines a subtype with a null range, the execution of the @fa is complete. Otherwise, the @fa is executed once for each value of the discrete subtype defined by the @fa that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a @i), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word @b is present, in which case the values are assigned in decreasing order. If a @fa with a @fa is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the @fa. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. Whether or not a @fa is present in a parallel loop, the total number of iterations of the loop represents an upper bound on the number of logical threads of control devoted to the loop. !comment The following is mainly to force a conflict. !corrigendum 5.5.3(0) @dinsa The @fa of a @fa with a @fa as its @fa shall contain an @fa, return statement, @fa, or @fa that leaves the loop only if the callable entity @i associated with the @fa has an Allows_Exit aspect specified True. @dinst The @fa of a @fa with a @fa as its @fa shall not contain an @fa. !ASIS No changes needed. !ACATS test An ACATS B-Test is needed for (1). No test is needed for (2). !appendix From: Randy Brukardt Sent: Friday, November 16, 2018 7:16 PM AI12-0251-1 defines the chunk syntax as: parallel [(chunk_specification)] for loop_parameter_specification but the Dynamic Semantics are: The chunk_specification is elaborated after the loop_parameter_specification is elaborated, and before any iterations are performed. Why is the elaboration in the opposite order of the textual appearance? I can't think of any reason that elaboration of one should have anything to do with elaboration of the other, so this order seems arbitrary. In such a case, I'd expect the order to be textual (that's certainly the order that a reader would expect). Moreover, you can't actually do anything until both are elaborated (you have to know how many chunks there are before you can do any iterations), so I don't see any implementation reason for this choice. The only reason that I can see for this choice is that it caused less change in the wording, but that shouldn't be the reason for any choice which has a run-time consequence. Is there something that I missed? I'd either leave the order unspecified (but that would be unusual for elaboration) or do the elaboration in textual order. I can't think of any other case where elaboration is done out-of-order within a single construct. *************************************************************** From: Randy Brukardt Sent: Friday, November 16, 2018 7:59 PM ... > Why is the elaboration in the opposite order of the textual > appearance? Note that arguably this order is outright wrong, since the existing wording says: For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is first elaborated. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. But how can you create "the loop parameter" when you don't know how many chunks there are? Since this creation doesn't have any actual effect, it's probably safe to ignore that wording, but still it doesn't make a ton of sense. **************************************************************** From: Tucker Taft Sent: Friday, November 16, 2018 9:22 PM I agree it makes more sense to elaborate in the textual order. **************************************************************** From: Randy Brukardt Sent: Wednesday, November 21, 2018 7:45 PM I'm trying to word this for the cleanup AI. The simple fix is just to reword the existing paragraphs as needed: Modify 5.5(9/5): [As modified by AI12-0119-1 and AI12-0251-1] For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is [first] elaborated{ after any chunk_specification (see below)}. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. If the reserved word parallel is present (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9), and its own copy of the loop parameter; otherwise a single logical thread of control performs the loop. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. Modify 5.5(9.1/5): [As modified by AI12-0251-1] If a chunk_specification is present in a parallel loop, it determines the maximum number of logical threads of control devoted to the parallel loop. The chunk_specification is elaborated {before}[after] the loop_parameter_specification is elaborated[, and before any iterations are performed]. If the chunk_specification is an /integer_/simple_expression, this elaboration evaluates the expression, and the value of the expression determines the maximum number of logical threads of control devoted to the parallel loop. If a discrete_subtype_definition is present, this elaboration elaborates the discrete_subtype_definition, and creates one or more logical threads of control, each having its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. If there is a chunk parameter, its assigned value increases with increasing values of the loop parameter. When the chunk_specification is elaborated, a check is made that the determined maximum number of logical threads of control is greater than zero. If this check fails, Program_Error is raised. ============ But this order is weird, because the second item elaborated comes first. Just reversing the paragraphs doesn't work, because the first paragraph has the definitions of "parallel loop" and "chunk" that are used in the second paragraph. So we'd have to rewrite this extensively to make that work, possibly something like: [The change information doesn't reflect the change in the order of the paragraphs.] {If the reserved word parallel is present in a loop_statement (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9).} If a chunk_specification is present in a parallel loop, it determines the maximum number of logical threads of control devoted to the parallel loop. The chunk_specification is {first} elaborated [after the loop_parameter_specification is elaborated, and before any iterations are performed]. If the chunk_specification is an /integer_/simple_expression, this elaboration evaluates the expression, and the value of the expression determines the maximum number of logical threads of control devoted to the parallel loop. If a discrete_subtype_definition is present, this elaboration elaborates the discrete_subtype_definition, and creates one or more logical threads of control, each having its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. If there is a chunk parameter, its assigned value increases with increasing values of the loop parameter. When the chunk_specification is elaborated, a check is made that the determined maximum number of logical threads of control is greater than zero. If this check fails, Program_Error is raised. For the execution of a loop_statement with the iteration_scheme including a loop_parameter_specification, the loop_parameter_specification is [first] elaborated{ after any chunk_specification}. This elaboration creates the loop parameter and elaborates the discrete_subtype_definition. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter. {For a parallel loop, each chunk has}[If the reserved word parallel is present (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with] its own separate logical thread of control [(see clause 9)], and its own copy of the loop parameter; {for other loops,}[otherwise] a single logical thread of control performs the loop. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. ----------- Is this enough better to use instead of the previous version? Or is this not worth the redo? There's a bit of duplication about the logical threads of control, but I thought we needed the reason for the chunks to appear up front. Any suggestions or improvements??? **************************************************************** From: Tucker Taft Sent: Wednesday, November 21, 2018 8:53 PM Let me give it a try. I think your second version is an improvement, but it still seems a bit weird to start talking about creating multiple loop parameters before we even elaborate the definition of the loop parameter. I'll send a reply at some point over the long weekend. **************************************************************** From: Randy Brukardt Sent: Wednesday, November 21, 2018 9:12 PM Sounds good. I probably won't look at it until Monday anyway (leaving for the holiday soon). Keep in mind that there is a small third paragraph that I didn't show (or change) in the version I sent. You might want to stick it into the blender as well as the parts I showed. *************************************************************** From: Tucker Taft Sent: Wednesday, November 21, 2018 9:39 PM Below is an attempt. I am not going to use "{}" or "[]" because I think it just adds to the confusion. If the reserved word parallel is present in a loop_statement (a /parallel/ loop), the iterations are partitioned into one or more /chunks/, each with its own separate logical thread of control (see clause 9). If a chunk_specification is present in a parallel loop, it is elaborated first, and the result of the elaboration determines the maximum number of chunks used for the parallel loop. If the chunk_specification is an /integer_/simple_expression, the elaboration evaluates the expression, and the value of the expression determines the maximum number of chunks. If a discrete_subtype_definition is present, the elaboration elaborates the discrete_subtype_definition, which defines the subtype of the chunk parameter, and the number of values in this subtype determines the maximum number of chunks. After elaborating the chunk_specification, a check is made that the determined maximum number of chunks is greater than zero. If this check fails, Program_Error is raised. For a loop statement that has an iteration scheme including a loop_parameter_specification, after elaborating the chunk_specification, if any, the loop_parameter_specification is elaborated. This elaboration elaborates the discrete_subtype_definition, which defines the subtype of the loop parameter. If the discrete_subtype_definition defines a subtype with a null range, the execution of the loop_statement is complete. Otherwise, the sequence_of_statements is executed once for each value of the discrete subtype defined by the discrete_subtype_definition that satisfies the predicates of the subtype (or until the loop is left as a consequence of a transfer of control). Prior to each such iteration, the corresponding value of the discrete subtype is assigned to the loop parameter associated with the given iteration. If the loop is a parallel loop, each chunk has its own logical thread of control with its own copy of the loop parameter; otherwise (a /sequential/ loop), a single logical thread of control performs the loop, and there is a single copy of the loop parameter. Each logical thread of control handles a distinct subrange of the values of the subtype of the loop parameter such that all values are covered with no overlaps. Within each logical thread of control, the values are assigned to the loop parameter in increasing order unless the reserved word reverse is present, in which case the values are assigned in decreasing order. If a chunk_specification with a discrete_subtype_definition is present, then the logical thread of control associated with a given chunk has its own copy of the chunk parameter initialized with a distinct value from the discrete subtype defined by the discrete_subtype_definition. The values of the chunk parameters are assigned such that they increase with increasing values of the ranges covered by the corresponding loop parameters. *************************************************************** From: Randy Brukardt Sent: Monday, November 26, 2018 10:22 PM Thanks for the wording. Three minor quibbles. First, you have "(a /parallel/ loop)". But the term we're defining here is "parallel loop", not just parallel. So the italics should include "loop" -- that is "(a /parallel loop/)". The same applies to "sequential loop". Second, you dropped part of the introduction, specifically "For [the execution of] a loop_statement..." The "the execution of" part seems needed to be consistent with the wording in the rest of the clause. (See while loops and unconditional loops). I presume you dropped it because it is weirdish to talk about elaboration of a chunk_specification before describing any part of the execution of a loop. However, I've convinced myself that it is OK, as the elaboration of a chunk_specification applies to a number of kinds of loops (it's supposed to apply to the "of" form loops, I think; Brad needs to include that in his AI12-0266-1 if it isn't there yet). While the following paragraph applies only to the execution of one kind of loop. (Side note: splitting that paragraph into a paragraph that is general, and a paragraph that talks about loop parameters, should help out Brad, because he only wants the first part anyway.) Third, a number of terms that were previously syntax terms lost their underscores. I put them back, seeing no reason to make unnecessary changes. I won't mention that a number of sentences end with an pair of blanks, and others with a single blank. :-) *************************************************************** From: Randy Brukardt Sent: Monday, November 26, 2018 10:36 PM One last thought on this rewording. Nowhere in this wording do we say when the loop parameter (or parameters) are created. That isn't very important (as there is no side-effects from such creation, as noted by an AARM Note), but it still seems strange. I wondered if we need a To Be Honest AARM note to say that we don't describe exactly when each loop parameter is created, since it doesn't have any visible effect, but it does have to be done before the associated iteration starts. Or something like that. Thoughts? ***************************************************************