!standard 5.5(9/5) 21-01-20 AI12-0416-1/06 !standard 6.1.2(17/5) !standard 6.4(7) !standard 6.4(9) !standard 6.4(10.1/2) !standard A.18(2/5) !standard A.18(5/3) !class Amendment 20-12-08 !status Amendment 1-2012 20-12-08 !status WG9 Approved 22-06-22 !status ARG Approved 16-0-0 21-01-20 !status work item 20-12-08 !status received 20-12-08 !priority Low !difficulty Easy !subject Fixups from Draft 26 review - part 2 !summary (1) We clarify the use of the term "container" in the introduction of the Containers child packages. (2) Define the term "smallest first". (3) Add a sentence explaining when a parallel construct with a loop_parameter_specification is complete. (4) The equivalence of a call on a prefixed view with a normal call is also true statically, so that the same Legality Rules are enforced on the prefix as would be enforced on a normal call. (5) Assertion expressions that apply to a call are included in the Global aspect even when the expressions are not enabled. (6) The rule about named associations following any positional associations applies only to a single actual_parameter_part. !problem (1) The term "container type" is used in A.18(12/5). But the only definition is associated with aggregates (see 4.3.5) and that isn't really appropriate here. (2) Is_Sorted "Returns True if the elements are sorted smallest first as determined by the generic formal "<" operator; otherwise, Is_Sorted returns False." Smallest first implies that the "<" has to return true for the elements, but that doesn't seem to account for equal elements. (3) Most parallel constructs have a definition of when the construct is complete. For instance, 5.5.2(10.2/5) ends with " In the absence of a transfer of control, the associated parallel construct of a parallel generalized iterator is complete when all of its logical threads of control are complete". There is similar wording in 5.6.1(3/5) for parallel blocks. But there is no such wording for parallel loops that iterates over a discrete range, formally one with a loop_parameter_specification. (4) 6.4(10.1/2) [a Dynamic Semantics paragraph] says that a prefixed view is equivalent to a call on the underlying subprogram. Equivalences defined in Dynamic Semantics only apply to runtime (not Legality). There are a number of Legality Rules that apply to calls, and in particular to parameters of calls, which need to be enforced on prefixed views (and in particular the prefix of a prefixed view). Two Legality Rules in 4.1.3 cover two important cases, but there don't appear to be any language that would, for instance, apply the anti-order dependence rules of 6.4.1 to the prefix of a prefixed view as if it is a parameter. (5) 6.1.2(17/5) includes "including any assertion expressions that might be evaluated as part of the call, including preconditions, postconditions, predicates, and type invariants." Does this include assertion expressions that are not enabled? One can read it either way. (6) 6.4(7) includes "Any positional associations shall precede any named associations." This could be read to include nested calls. But we want a call like: Func1 (Param1 => True, Param_2 => Func2 (123)) to be legal. !proposal (1) Rewrite the basic introductory paragraph to clarify the meaning of "container" by itself and mention that we can talk about more specific things as well. (2) Define "smallest first". (3) Add a definition of when a parallel construct with a loop_parameter_specification is complete. (4) Move 6.4(10.1/2) to Static Semantics (after 6.4(9)). (5) Add "(even if not enabled)" to 6.1.2(17/5) and make other improvements to the wording. (6) Prefix the rule with: "For the parameter_associations of a single actual_parameter_part or iterator_actual_parameter_part,". !wording [Editor's note: These changes were applied to Draft 28 of the Ada 202x RM, even though they have not yet been approved, in order that that draft be as accurate as possible.] (1) Modify A.18(2/5): A variety of sequence and associative containers are provided. Each container {package defines}[includes] a cursor type{ as well as a container type}. A cursor is a reference to an element within a container. Many operations on cursors are common to all of the containers. A cursor referencing an element in a container is considered to be overlapping only with the element container object itself. AARM Discussion: We use the term "container" alone when it is clear from context what kind of entity (package, type, or object) that we are talking about. Otherwise, we use "container package", "container type", or "container object". Note that "container type" is defined in 4.3.5 for a different usage; in all of A.18 we mean "container type" to be one of the primary types declared in the child packages of package Containers, such as Vector, List, or Map. (2) Modify A.18(5/3): When a formal function is used to provide an ordering for a container, it is generally required to define a strict weak ordering. A function "<" defines a /strict weak ordering/ if it is irreflexive, asymmetric, transitive, and in addition, if x < y for any values x and y, then for all other values z, (x < z) or (z < y).{ Elements are in a /smallest first/ order using such an operator if, for every element y with a predecessor x in the order, (y < x) is false.} AARM Reason: Given a "<" operator that provides a strict weak ordering, knowing that (y < x) is false is enough to know that (x <= y) is true. For a strict weak ordering, (x = y) when both (x < y) and (y < x) are false. Therefore, it is not necessary to use the "=" operator or test (x < y). We only need to discuss adjacent elements since a strict weak ordering is transitive. (3) Add to the end of 5.5(9/5): In the absence of a transfer of control, the associated parallel construct of a loop_parameter_specification is complete when all of its logical threads of control are complete. Add an AARM note: Discussion: The rules for completing a parallel construct when there is a transfer of control are given in 5.1. (4) Move 6.4(10.1/2) after 6.4(9), under the heading "Static Semantics". (5) Modify 6.1.2(17/5): The Global aspect for a callable entity defines the global variables that might be referenced as part of a call on the entity, including any assertion expressions that [might be evaluated as part of]{apply to} the call{ (even if not enabled)}, including preconditions, postconditions, predicates, and type invariants. (6) Modify 6.4(7): A parameter_association is named or positional according to whether or not the formal_parameter_selector_name is specified. {For the parameter_associations of a single actual_parameter_part or iterator_actual_parameter_part, any}[Any] positional associations shall precede any named associations. Named associations are not allowed if the prefix in a subprogram call is an attribute_reference. !discussion (1) The term "container" appears to be used to mean whatever is convenient in paragraph A.18(2/2). The first sentence sounds like it could mean any of package/type/object. The second sentence only makes sense for a package (nothing is "included" in a type or object). The third sentence works for a type or object, but not a package (can't reference an element in a package, only within an object or [abstractly] a type). The fourth sentence is like the first. We try to clarify the meaning a bit. It probably would be better to have a more extensive terminology paragraph before this one, but even if we did that, this one would need to be less vague. We use the terms "container type" and "container package" in other wording, and it is best to introduce them early. (2) If elements A and B are equal, then A < B and B < A are both False. That means that the correct "smallest first" test isn't simply A < B (if A is the "first" element), but (A < B) or (not B < A). (This corresponds to less than or equal.) Because of the requirements of a "strict weak ordering", if (A < B) is True, then B < A has to be False. So testing (not B < A) is sufficient. We define "smallest first" accordingly. We use "predecessor" as that is the term used in defining the list containers, and it works as an English term when applied to the Vector containers and to arrays. (3) While 7.6.1(2/2) makes it clear that a sequential construct is "complete" when its execution ends, it is much less clear when the execution ends for a parallel construct made up of several threads, all of which will end at different times. We felt it necessary to explain this for other parallel constructs, and it seems necessary to do so for normal parallel loops as well. Note that we talk about the "associated parallel construct" so that this wording clearly applies to parallel reductions and any other parallel constructs using a loop_parameter_specification (as does the wording for other kinds of iterators). It's not just about parallel loops. (4) The rules that are needed for a call on a prefixed view include: * Calling an abstract subprogram with a nondispatching call is illegal; * An in out or out parameter shall be a variable; * The anti-order-dependence rules of 6.4.1; * The accessibility checks on an aliased parameter of a function. In particular, rules that apply to actual parameters have to apply to the prefix of a prefixed view. It isn't practical to copy all of those into 4.1.3. The first rule (and any rule that depends only on the subprogram's properties) is covered by the sentence in 4.1.3(9.2/3): "The selected_component denotes a view of this subprogram that omits the first formal parameter." But this does not cover any rule that applies to the actual parameter of a call (since the prefix is not defined to be such a parameter). The equivalence in 6.4(10.1/2) covers runtime rules, but it doesn't apply at compile-time (as noted in the question). In order to make that equivalence apply at compile time, we need to change the equivalence to Static Semantics. Note that the Legality Rules 4.1.3(13.1/5) and 4.1.3(13.2/2) are NOT redundant. They apply not just to calls, but also to uses of a prefixed view that are not a call (in particular, a renaming, use as an actual for a formal subprogram, or use as the prefix of 'Access [the last is only possible for access-to-protected-procedures]). It's likely that there are still some rules that should fail for a prefixed view that is not a call (especially if prefixed views are extended to untagged types in a future Ada). These cases seem unlikely enough that it isn't worth worrying about them now. For instance, it seems that one could "hide" a local object in a renaming and evade the accessibility check on an aliased parameter of a function. But for that to happen, one needs a local renaming of a prefixed view of a function returning a composite type, with the prefix being a local, AND the function being called in a library-level context (such as being used to initialize an allocator of a library-level access type). [Editor's note: No simple fix seems available for this particular issue, which is why we chose to ignore it at this point.] (5) We try to avoid having Legality Rules depend on whether an assertion is enabled. That prevents the act of enabling an assertion from changing the legality of a program unit. The "might" in the original wording was intended to convey that, but it is clearly not enough to make that point. So we explicitly mention that assertion expressions that are "not enabled" are included. (6) We need to clarify that we are talking only about a single list of parameters. Otherwise, the rule could be interpreted textually. We have fixed the wording of a number of other rules over the years that have similar nesting problems (for instance, the naming of subtypes in access-to-subprogram types are not the subtypes associated directly with conformance of a parameter list). Now that it has been noted, this one should be fixed, too. Note that iterator_actual_parameter_part also uses parameter_associations, so this rule also applies to them and we want that to remain the case. Generic instantiations has their own rule for this; it doesn't need a fix since instances cannot be nested. !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 and @fa, if any, the @fa is elaborated. This 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 conditionally 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. In the absence of a transfer of control, the associated parallel construct of a @fa is complete when all of its logical threads of control are complete. 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. !corrigendum 6.1.2(0) @dinsc See the conflict file for the changes. !corrigendum 6.4(7) @drepl A @fa is @i or @i according to whether or not the @i@fa is specified. Any positional associations shall precede any named associations. Named associations are not allowed if the @fa in a subprogram call is an @fa. @dby A @fa is @i or @i according to whether or not the @i@fa is specified. For the @fas of a single @fa or @fa, any positional associations shall precede any named associations. Named associations are not allowed if the @fa in a subprogram call is an @fa. !corrigendum 6.4(9) @dinsa A subprogram call shall contain at most one association for each formal parameter. Each formal parameter without an association shall have a @fa (in the profile of the view denoted by the @fa or @fa). This rule is an overloading rule (see 8.6). @dinst @s8<@i> If the @fa or @fa of a subprogram call denotes a prefixed view (see 4.1.3), the subprogram call is equivalent to a call on the underlying subprogram, with the first actual parameter being provided by the @fa of the prefixed view (or the Access attribute of this @fa if the first formal parameter is an access parameter), and the remaining actual parameters given by the @fa, if any. !corrigendum 6.4(10.1/2) @ddel If the @fa or @fa of a subprogram call denotes a prefixed view (see 4.1.3), the subprogram call is equivalent to a call on the underlying subprogram, with the first actual parameter being provided by the @fa of the prefixed view (or the Access attribute of this @fa if the first formal parameter is an access parameter), and the remaining actual parameters given by the @fa, if any. !corrigendum A.18(2/2) @drepl A variety of sequence and associative containers are provided. Each container includes a @i type. A cursor is a reference to an element within a container. Many operations on cursors are common to all of the containers. A cursor referencing an element in a container is considered to be overlapping with the container object itself. @dby A variety of sequence and associative containers are provided. Each container package defines a @i type as well as a container type. A cursor is a reference to an element within a container. Many operations on cursors are common to all of the containers. A cursor referencing an element in a container is considered to be overlapping only with the element itself. !corrigendum A.18(5/3) @drepl When a formal function is used to provide an ordering for a container, it is generally required to define a strict weak ordering. A function "<" defines a @i if it is irreflexive, asymmetric, transitive, and in addition, if @i < @i for any values @i and @i, then for all other values @i, (@i < @i) or (@i < @i). @dby When a formal function is used to provide an ordering for a container, it is generally required to define a strict weak ordering. A function "<" defines a @i if it is irreflexive, asymmetric, transitive, and in addition, if @i < @i for any values @i and @i, then for all other values @i, (@i < @i) or (@i < @i). Elements are in a @i order using such an operator if, for every element @i with a predecessor @i in the order, (@i < @i) is false. !ASIS No ASIS effect. !ACATS test No ACATS Tests needed. !appendix From the RM Review of Jean-Pierre Rosen, October 2020 A.18(12/5) For an instance I of a container package with a container type C, the specific type T of the object returned from a function that returns an object of an iterator interface, as well as the primitive operations of T, shall be nonblocking. The Global aspect specified for T and the primitive operations of T shall be (in all, out synchronized) or a specification that allows access to fewer global objects. I find this paragraph strange. What is a "container type"? The type on which the container is instantiated? Then it would rather be the contained type... And "C" is not referred to anywhere. **************************************************************** From: Randy Brukardt Sent: Tuesday, December 8, 2020 1:37 AM In Jean-Pierre's review, he comments on the definition of Is_Sorted: The case of equal elements is not addressed. Shouldn't it be: Returns True if the elements are sorted smallest first as determined by the generic formal "<" operator {and the generic formal "=" operator} The direct answer here is clear: No, we don't use the formal "=" for sorting. Doing so would greatly complicate the rules for "<" as one would need to worry about interactions with "=" as well as defining a strict weak ordering. Moreover, we want the vector sort and the array sort to work the same way, and there is no "=" passed into the array sort. And we want to support multiple sorts for each container (or array), just using different "<" operations, the equality of elements might even be different for each ordering operation. But there still seems to be a problem here, in that the wording doesn't take into account the possibility of equal elements. Elements are "equal" if neither A < B nor B < A are True. "Smallest first" seems to imply that A < B for all adjacent A and B, but that's not right. The actual requirement has to be (A < B) or (not B < A) I'm not sure of the best way to fix this. The pedantic solution would be to formally define "smallest first" (that's never done in the RM). We could put that directly below the "strict weak ordering" paragraph in A.18. That would be something like: Elements are in a /smallest first/ order using an operator "<" if for an element A that precedes an element B, (A < B) or (not B < A) is True. AARM Reason: For elements that are considered equal for a particular "<" operator, neither A < B nor B < A are true. Or we could add a To Be Honest AARM note somewhere that says something similar. Or we could somehow try to handle equal elements explicitly in the wording. (I don't have an idea for this.) I do think we need to say something somewhere, as we certainly mean to allow sorting equal elements and for Is_Sorted to give a meaningful answer if there are equal elements. And it's not obvious, as J-P's comment shows. Thoughts? **************************************************************** From: Randy Brukardt Sent: Tuesday, December 8, 2020 9:11 PM ... > Or we could somehow try to handle equal elements explicitly in the > wording. > (I don't have an idea for this.) Another idea would be to write Is_Sorted as an expression function, in which case no wording would be needed. The sort operation can then be defined in terms of Is_Sorted, again eliminating the English wording. But that wouldn't help the array sorts, which don't have an Is_Sorted operation. > I do think we need to say something somewhere, as we certainly mean to > allow sorting equal elements and for Is_Sorted to give a meaningful > answer if there are equal elements. And it's not obvious, as J-P's > comment shows. > > Thoughts? Still waiting for thoughts. :-) I haven't written this up yet, as I don't know the solution to use. **************************************************************** From the AARM review of Steve Baird, October 2020 In 6.1.2(17/5) we talk about assertion expressions. Interactions with assertion policy need to be clarified. **************************************************************** Editor's response to the above (January 2021) Clearly, we don't want Legality to change when something is enabled or disabled, so I'd suggest adding "even if they are disabled". Tucker suggests rewording as: ... defines the global variables that might be referenced as part of a call on the entity, including any assertion expressions that [might be evaluated as part of]{apply to} the call{ (even if not enabled)}, including preconditions, postconditions, predicates, and type invariants. **************************************************************** From the AARM review of Steve Baird, October 2020 I suppose we *could* clarify that the rule 6.4(7): Any positional associations shall precede any named associations. applies separately to each actual_parameter_part. For example, the following function call is legal: Func1 (Param1 => True, Param_2 => Func2 (123)) even though a positional association "follows" a named association. **************************************************************** Editor's response to the above (January 2021) This actually bothers me enough to worry about it. We've generally fixed such issues when they've been noted, for instance for subtypes in subprogram declarations. We probably should prefix this rule with "For the parameter_associations of a single actual_parameter_part or iterator_actual_parameter_part,". ****************************************************************