!standard 3.2.4(0) 12-03-15 AI05-0269-1/10 !standard 3.5(56/2) !standard 3.10.1(13) !standard 4.1.5(0) !standard 4.1.6(0) !standard 4.5.2(2) !standard 4.5.2(27) !standard 4.5.2(28) !standard 4.5.2(30.2/2) !standard 4.5.7(0) !standard 4.8(3/1) !standard 4.9(11) !standard 4.9(33) !standard 5.5.2(0) !standard 6.1.1(0) !standard 7.3(15) !standard 7.3.1(5/1) !standard 7.3.2(0) !standard 7.4(2) !standard 7.6(17/2) !standard 7.6.1(13/2) !standard 9.6.1(42/2) !standard 13.3(65) !standard 13.11(21) !standard 13.11.3(5) !standard 13.11.4(0) !standard 13.12(7/2) !standard 13.13.2(26) !standard A.3.5(0) !standard A.4.11(0) !standard A.16.1(0) !standard A.17(19/2) !standard A.18.2(147/2) !standard A.18.2(230/2) !standard A.18.3(86/2) !standard A.18.3(144/2) !standard A.18.4(41/2) !standard A.18.5(61/2) !standard A.18.6(94/2) !standard A.18.7(36/2) !standard A.18.7(96/2) !standard A.18.8(85/2) !standard A.18.9(113/2) !standard A.18.10(0) !standard A.18.18(0) !standard A.18.21(0) !standard A.18.22(0) !standard A.18.23(0) !standard A.18.24(0) !standard B.1(1) !standard B.1(40) !standard B.1(51) !standard B.3(23) !standard B.3.3(1/2) !standard D.2.4(11/2) !standard D.10(10) !standard D.14(11/2) !standard D.16.1(0) !standard E.2(5) !standard E.2(6) !standard E.2.2(14/2) !class Amendment 11-11-09 !status Amendment 2012 12-01-12 !status ARG Approved 8-0-2 12-02-26 !status work item 11-11-09 !status received 11-07-20 !priority Low !difficulty Easy !qualifier Error !subject Editorial comments on Draft 14 !summary Handle editorial comments on Draft 14 of the Ada 2012 Standard. !proposal (1) Drop Pragma Preelaborate from D.16.1(3/3) (the package depends on Ada.Real_Time, which is not preelaborated. (2) The Implementation Advice for bounded maps and sets ought to include the kind, so the M.3 summary does not look repetitive. (3) We should always use "holder" as an adjective; using "holder container" if no other option exists. There is only one element in a holder, so use "the element" instead of "elements". (4) There is no type named "Root_Subpool_Type", this should be fixed. (5) 13.11.3(5/3) does not tell us where the aspect is allowed. (6) The list of packages for 13.12.1(2.1/3) includes Interfaces.C.Pointers, which is a generic package. But the wording does not strictly apply to it (a generic package is not a package, and a instance of it is not a language-defined package). This should be fixed. (7) "The aspect Storage_Size" in 13.3(65.2/3) is inconsistent with the following rules which use "The Storage_Size aspect". (8) The term "invididual membership test" is used twice before it is defined, which is confusing and unnecessary. Add a separate definition for the term before it is used. (9) It's not clear whether the first "designated type" talked about in 4.5.2(30.3/3) is that of the tested type or of the simple_expression. Clarify that. (10) 4.9(32.5/3) talks about how the selecting_expression "is static and is not covered by" a discrete_choice_list. This doesn't make much sense, because a discrete_choice is defined to cover a value by 3.8.1(9) (not an expression). "Value" (of the selecting_expression) needs to be mentioned somehow. (11) The introduction of 3.2.4 is the first place that aspects and aspect_specifications are mentioned in the Standard. We need a strong forward reference. (12) 3.2.4(7/3) says "a static expression that does not raise any exception;", but an expression that could raise an exception is not static by 4.9(34/3), so the part about the exception is just noise. (13) We shall not use "shall" in notes, so 3.10.1(13.1/3) should be fixed. (14) There are too many expecteds in 4.1.5(5/3). Get rid of one of them. (15) "All of such" should be "all such" in 4.1.6(3/3). (16) 3.5(56.1/3) is confusing. Please clarify. (17) The first sentence of A.16.1(16/3) ends abruptly. Please improve. (18) In A.17(19/3), the second ""variable" should be plural. (19) In Annex B, we usually say "the aspect". The first two uses in B.1(1/3) say "aspect " instead. Please change. (20) It would be nice for a type to be given in the example of B.1(51/3). (21) In B.3.3(1/3), "leaves no space" is really informal; "allocates no space" would be better. (22) 13.13.2(26) says that the discriminants are written with "S'Write"; but S in this context is the discriminanted record type. This should be fixed. (23) 13.11(21.5/3) says that "The Alignment parameter is at least D'Alignment ...". This allows passing 5 if D'Alignment is 4, and is generally weird. (24) The introductory text for A.18.2(147.13/3) and many others is clunky. (25) "the" loop parameter should be "a" loop parameter in A.18.2(230.2/3) and many other functions. We also should add cross-references to where these things are defined. (26) The definition of "decendant" and "ancestor" in A.18.10 is inconsistent (and inconsistent with the use of these terms elsewhere in the Standard). Some other text is unclear. (27) The definition of Separate_Interrupt_Clocks_Supported should have a forward reference to D.14.3 where it is used. (28) D.10(10) raises Program_Error if a second is suspended on a suspension object; D.10(10.1/3) does not have this rule. That appears to be an omission. (29) D.2.4(11/3) would allow priority inversion if Yield_To_Higher was called during a protected action. In addition, it isn't clear that this permission only applies to partitions using the Non_Premptive_FIFO_Withing_Priorities policy. (30) In 6.1.1(32/3) [Draft 14], "primitive" is used as a noun; this should be "primitive subprogram". (31) 7.3(15) is not really a definition, but the italics imply that it is. Now that we've decided that this definition is in 3.4 (see AI-0110-1), this wording should reflect that. (32) 7.3.2(22/3) and it's AARM note are confusing, because it is not clear how the rules, particular 7.3.2(12/3) are applied. In addition, 7.3.2(12/3) doesn't seem to require checking intermediate types when the conversion "crosses" multiple types. (33) 7.4(2/3) is awkward, as the "unless" seems to bind with "shall". (34) 7.6(17.1/3) has the definition on the second use of the term. Move it to the first use. (35) 7.6.1(13/3) talks about an anonymous object being "part of the actual parameter expression". But of course it can't be part of the expression, it's part of the result of evaluating the expression. (36) 4.5.2(2/3) contains: "...or is convertible to and with accessibility level appropriate for a given access type." "...to and with..." is awkward, it makes the phrase hard to comprehend. [Canada informal comment] (37) 4.5.7(19/3) has a stray comma. [Canada informal comment] (38) 4.8(3/3) is hard to understand. Recommend adding "which is" before "the type used to identify a subpool". [Canada informal comment] (39) In 6.1.1(29/3), "The checks" is vague; this should say "The precondition checks". [Canada informal comment] (40) In 7.3.1(5.1/3), "some more" is poor wording, try to say something else. [Canada informal comment] (41) In 9.6.1(42/3), the wording is now "the result of subtracting A, and B". If we want to say "subtracting" it should be "A from B", not "A, and B". [Canada informal comment] (42) 4.5.7(17/3) is hard to read; perhaps consider a bulleted list. [Canada informal comment] (43) 13.3(38/3) should say "specifying the Pack aspect as True" rather than "to True" as currently. [Canada informal comment] (44) In 13.11.4, some functions have mode "in" on their parameters, while some procedure parameters are missing the mode. [Canada informal comment] (45) In A.3.5, some descriptions end with "; otherwise returns False", others end with ", otherwise returns False". These should all use the semicolon form. [Canada informal comment] (46) In A.4.11, 60/3 is unusual in that "otherwise" comes at the end rather than in the middle; 92/3 and 104/3 mention the result while similar functions don't elsewhere in this section. [Canada informal comment] (47) B.1(40/3) should say "the aspect Export" as it is talking about specifying it as True. [Canada informal comment] (48) E.2(6/3) is confusing as written. We suggest using "earlier one in the hierarchy" instead of "earlier one" in E.2(5/3), and then making it clear that E.2(6/3) is referring to this. [Canada informal comment] (49) 7.3.1(14-18/3) is awkward because of the partial sentence at the end. Can this be improved? [Canada informal comment] (50) Predicate static should allow "and then" and "or else"; otherwise organizations with coding standards that require these will have to make a special exception for static predicates. (51) There should be an implementation permission for implementation-defined Profiles; and the permission for Restrictions should be worded consistently with that for pragmas. (52) In 4.1.5(2/3), "name" should be in the syntax font. (53) In 5.5.2(7/3), "iterator cursor subtype" should be "iteration cursor subtype", as this is the term defined in 5.5.1. (54) 1(2) gives a list of the most important of the standard package. This list should mention the containers, as these are argubly the most important of the packages. This is especially odd given that the Introduction does mention these in the equivalent list (see paragraph 42.1/2). (55) In D.16.1, the package needs a "with" of Ada.Task_Identification, and references on each use of an entity from that package. [Canada NB] (56) In E.2.2(14.1/3), the bullet should end with a cross-reference "(see 9.5)", as several other similar bullets in the area have such cross-references for unfamiliar terms. [Canada NB] (57) In A.4.11, paragraph 50/3 should come before 49/3 - describe input first then output for the Encode and Convert functions, like the Decode functions (51/3). [Canada NB] (58) A.16.1(28/3) should include "(including directories and special files)", as the text appears in A.16.1(32/3) and a number of places in A.16, so it seems it should be here as well. [Canada NB] (59) Add an array iteration example to 5.5.2. [Canada NB] (60) 4.9(11) is hard to read, consider rewording. [Canada NB] (61) A.18.10(173/3) (Append_Child) says: "Equivalent to Insert_Child (Container, Parent, Last_Child (Container, Parent), New_Item, Count)." But this will insert the item in front of the last item. The third parameter here should be No_Element. (62) B.3(23/3) should include "with Pack" to be consistent with the other array declarations in this package. [Ada-Europe comment, ARG direction, see !discussion] !wording (1) Remove pragma Preelaborate from D.16.1(3/3). (2) Add "hashed" to A.18.21(21/3), "ordered" to A.18.22(18/3), "hashed" to A.18.23(20/3), and "ordered to A.18.24(17/3), in front of "map" or "set". (3) Change "holder" to "holder container" in A.18.18(70,72,74/3). Change "elements" to "the element" in A.18.18(73/3). (4) Replace "Root_Subpool_Type" with "Root_Subpool" in 13.11.4(19/3). (5) Modify 13.11.3(5/3): The language-defined aspect Default_Storage_Pool may be {specified for a generic instance; it defines} [used to define] the default pool for access types within an instance. (6) Modify 13.12.1(2.1/3): There are no usage names that denote declarations with implementation-defined identifiers that occur within language-defined packages {or instances of language-defined generic packages}. (7) Modify 13.3(65.2/3): Storage_Size The [aspect] Storage_Size {aspect} ... (8) Add before 4.5.2(27/3): An *individual membership test* is the membership test of a single membership_choice. Remove the italics from 4.5.2(28/3). (9) Modify 4.5.2(30.3/3): "...if the designated type {of the tested type} is tagged ..." (10) Modify 4.9(32.5/3): "...whose /selecting_/expression is static and {whose value} is not covered by the corresponding discrete_choice_list..." (11) Add to the end of 3.2.4(1/3): General rules for aspects and aspect_specifications are found in chapter 13 (13.1 and 13.3.1 respectively). (12) Modify 3.2.4(7/3): "a static expression[ that does not raise any exception];" (13) Modify 3.10.1(13.1/3): "...statement {cannot}[shall not] be of an...". (14) Replace 4.1.5(5/3) by: "The expected type for the reference_object_name in a generalized_reference is any reference type." (15) Modify 4.1.6(3/3): "... All [of] such functions ..." (16) Replace 3.5(56.1/3) with: An implementation may extend the Wide_Wide_Value, Wide_Value, and Value attributes of a character type to accept strings of the form "Hex_hhhhhhhh" (ignoring case) for any character (not just the ones for which Wide_Wide_Image would produce that form -- see 3.5.2), as well as three-character strings of the form "'X'", where X is any character, including nongraphic characters. (17) Modify A.16.1(16/3): In addition to the operations provided in package Directories.Hierarchical_File_Names, {the} operations in package Directories can be used {with hierarchical file names}. In particular, functions Full_Name, Base_Name, and Extension {provide additional capabilities for}[are usable with] hierarchical file names. (18) Modify A.17(19/3): "...all existing environment variable{s}..." (19) Change "Specifying aspect Import to..." to "Specifying the Import aspect to..." and similarly for Export in B.1(1/3). (20) Replace the example B.1(51/3) with: package Fortran_Library is function Sqrt (X : Float) return Float with Import => True, Convention => Fortran; type Matrix is array (Natural range <>, Natural range <>) of Float with Convention => Fortran; function Invert (X : Matrix) return Matrix with Import => True, Convention => Fortran; end Fortran_Library; (21) Modify B.3.3(1/3): "...[leaves]{allocates} no space...". (22) Modify 13.13.2(26): "... S'Output first writes the discriminants (using [S'Write]{the Write attribute of the discriminant type} for each), and S'Input first reads the discriminants (using [S'Read]{the Read attribute of the discriminant type} for each)." (23) Modify 13.11(21.5/3): "... The Alignment parameter is {a nonzero integral multiple of}[at least] @i'Alignment if @i is a specific type, and otherwise is {a nonzero integral multiple}[at least] of the alignment of the specific type identified by the tag of the object being created{; it is unspecified if there is no such value}. ..." (24) Modify A.18.2(147.13/3), A.18.2(147.16/3), A.18.3(86.6/3), A.18.3(86.9/3), A.18.4(41.6/3), A.18.4(41.9/3), A.18.7(36.5/3), A.18.7(96.10/3), A.18.10(125/3), A.18.10(126/3): "This function (combined with the and Implicit_Dereference aspects) provides a convenient way to gain access to {an}[the] individual element[s] of a {vector|list|map|set|tree}[container] {given}[starting with] ." [Note: The text is to be the same as in the original paragraph; it is one of the enclosed options.] (25) Modify A.18.2(230.2/3), A.18.2(230.4/3), A.18.3(144.2/3), A.18.3(144.4/3), A.18.5(61.2/3), A.18.6(94.2/3), A.18.6(94.4/3), A.18.8(85.2/3), A.18.9(113.2/3), A.18.9(113.4/3), A.18.10(155/3), A.18.10(157/3), A.18.10(217/3): "...Iterate returns a iterator object {(see 5.5.1)} that will generate a value for [the] {a} loop parameter {(see 5.5.2)} designating each node in Container, ..." (26) Modify A.18.10(3/3): ... The root node provides a place to add nodes to an otherwise empty tree and represents the [bottom] {base} of the tree. Modify A.18.10(4/3): A node that has no children is called a leaf node. The ancestors of a node are the {node itself, its} parent node, the parent of the parent node, and so on until a node with no parent is reached. Similarly, the descendants of a node are the {node itself, its} child nodes, the children of each child node, and so on. Modify A.18.10(5/3): The nodes of a subtree can be visited in several different orders. For a depth-first order, [the last step of] {after} visiting a node{,} [is to visit] the nodes of its child list {are each visited in depth-first order, with each child visited in natural order (first child to last child)}[order, recursively]. Modify A.18.10(140/3): the subtree designated by Position (that is, {all descendants of} the node designated by Position [and all of the descendant nodes of that node] {including the node itself}) Modify A.18.10(174/3): ... Otherwise, Delete_Children removes (from Container) all of the [child nodes of Parent along with their descendant nodes] {descendants of Parent other than Parent itself}. Modify A.18.10(178/3) and A.18.10(181/3): ... if Position designates an ancestor of Parent [or is equal to Parent] {(including Parent itself)} ... Modify AARM notes A.18.10(178.a/3, 181.a/3, 187.a/3): Reason: We can't allow moving the subtree of Position to a {proper} descendant node of the subtree, as the descendant node will be part of the subtree being moved. ... Modify A.18.10(186/3): * if Source_Parent is an ancestor of Target_Parent {other than Target_Parent itself}, then Constraint_Error is propagated; else Modify A.18.10(186/3, 188/3, 190/3): ... the child elements (and [their] {the further} descendants) of Source_Parent ... Modify A.18.10(190/3): ... If Source_Parent is an ancestor of Target_Parent {other than Target_Parent itself}, then ... (27) Add "(see D.14.3)" to the end of D.14(11/3). (28) Add "Program_Error is raised upon calling Suspend_Until_True_And_Set_Deadline if another task is already waiting on that suspension object." as the penultimate sentence of D.10(10.1/3). (29) Replace D.2.4(11/3) with: Since implementations are allowed to round all ceiling priorities in subrange System.Priority to System.Priority'Last (see D.3), an implementation may allow a task of a partition using the Non_Premptive_FIFO_Within_Priorities policy to execute within a protected object without raising its active priority provided the associated protected unit does not contain any subprograms with aspects Interrupt_Handler or Attach_Handler specified, nor does the unit have aspect Interrupt_Priority specified. When the locking policy (see D.3) is Ceiling_Locking, an implementation taking advantage of this permission shall ensure that a call to Yield_to_Higher that occurs within a protected action uses the ceiling priority of the protected object (rather than the active priority of the task) when determining whether to preempt the task. AARM Reason: We explicitly require that the ceiling priority be used in calls to Yield_to_Higher in order to prevent a risk of priority inversion and consequent loss of mutual exclusion when Yield_to_Higher is used in a protected object. This requirement might lessen the value of the permission (as the current Ceiling_Priority will have to be maintained in the TCB), but loss of mutual exclusion cannot be tolerated. The primary benefit of the permission (eliminating the need for preemption at the end of a protected action) is still available. As noted above, an implementation-defined locking policy will need to specify the semantics of Yield_to_Higher, including this case. (30) Modify 6.1.1(32/3): "...primitive {subprogram}..." (three places). (31) In 7.3(15), replace the italisized "characteristics" with "characteristics (see 3.4)", as the definition of these things live there, not here. (32) Replace 7.3.2(12/3) with: For a view conversion, outside the immediate scope of T, that converts from a descendant of T (including T itself) to an ancestor of type T {(other than T itself), a check is performed on the part of the object that is of type T: * after assigning to the view conversion; and * after successful return from a call that passes the view conversion as *in out* or *out* parameter. Replace 7.3.2(22/3) and the AARM note with: For a call of a primitive subprogram of type NT that is inherited from type T, the specified checks of the specific invariants of both the types NT and T are performed. For a call of a primitive subprogram of type NT that is overridden for type NT, the specified checks of the specific invariants of only type NT are performed. AARM Proof: This follows from the definition of a call on an inherited subprogam as view conversions of the parameters of the type and a call to the original subprogram (see 3.4), along with the normal invariant checking rules. In particular, the call to the original subprogram takes care of any checks needed on type T, and the checks required on view conversions take care of any checks needed on type NT, specifically on *in out* and *out* parameters. We require this in order that the semantics of an explicitly defined wrapper that does nothing but call the original subprogram is the same as that of an inherited subprogram. (33) In 7.4(2/3), replace the last sentence with: "Unless the Import aspect (see B.1) is True for a deferred constant declaration, the deferred constant declaration requires a completion, which shall be a full constant declaration (called the *full declaration* of the deferred constant)." (34) Replace the latter part of 7.6(17.1/3) with: For such an assignment, the anonymous object might be *built in place*, in which case the assignment does not involve any copying. Under certain circumstances, the anonymous object is required to be built in place. In particular: (35) Modify 7.6.1(13/3): "...If such an anonymous object is part of {the result of evaluating} the actual parameter expression for..." (36) Modify 4.5.2(2/3): "...to and {has}[with]..." (37) Modify 4.5.7(19/3): "... case_statement (see 5.4)[,]{ also} apply to the discrete_choices..." (38) Modify 4.8(3/3): "... descended from Subpool_Handle, {which is} the type used to identify a subpool, ..." (39) Modify 6.1.1(29/3) [Probably will be 6.1.1(34/3) in Draft 15 - Editor] "The {precondition} checks are performed..." (40) Modify 7.3.1(5.1/3) "...or a descendant only through record extensions of {a}[some] more distant ancestor." (41) Modify 9.6.1(42/4) "...time zone of Calendar{ from}[, and] UTC time, ..." (42) Modify 4.5.7(17/3) "... none shall be dynamically tagged{. In this case,}[;] the conditional_expression..." (43) Modify 13.3(38/3): "...Pack aspect {as}[to] True..." (44) In 13.11.4, parameter modes should be given on all parameters except for function parameters with mode "in". (45) In A.3.5, replace all occurrences of ", otherwise" with "; otherwise". (46) In A.4.11, make the following modifications: A.4.11(60/3): "... If so, returns the scheme corresponding to the BOM; {otherwise, }returns the value of Default[ otherwise]." A.4.11(92/3) "Returns the result of decoding Item, which is encoded in UTF-8[, and returns the corresponding Wide_String value]." A.4.11(104/3) "Returns the result of decoding Item, which is encoded in UTF-8[, and returns the corresponding Wide_Wide_String value]." (47) Modify B.1(40/3): "...specifying {the} Export {aspect} as True is supported." (48) Modify E.2(5/3): "...of that category or an earlier one {in the hierarchy}, except that..." Replace E.2(6/3) with: "The overall hierarchy (including declared pure) is as follows, with a lower-numbered category being "earlier in the hierarchy" in the sense of the previous paragraph):" (49) Modify 7.3.2(14/3): {An invariant is checked upon}[Upon] successful return from a call on any subprogram or entry that: (50) Add after 3.2.4(12/3): "* a short-circuit control form where both operands are predicate-static; or" Modify 7.3.2(18/3): {The}[the] check is performed on each such part of type T. (51) Delete 13.12(7/2). Add before 13.12(9/2) (but under the Implementation Permissions header: An implementation may provide implementation-defined restrictions; the identifier for an implementation-defined restriction shall differ from those of the language-defined restrictions. Add after 13.12(14/2): Implementation Permissions An implementation may provide implementation-defined usage profiles; the identifier for an implementation-defined usage profile shall differ from those of the language-defined usage profiles. (52) In 4.1.5(2/3), "name" should be in the syntax font. (53) In 5.5.2(7/3), replace "iterator cursor subtype" with "iteration cursor subtype". (54) Add "containers" to the list in 1(2): "..., [and] random number generation{, and definition and use of containers}." (55) Add "with Ada.Task_Identification;" to D.16.1(3/3). In D.16.1(10-13/3), add "Ada.Task_Identification" in front of "Task_Id" and "Current_Task". [Note: Not using a "use clause" for Task_Id is consistent with the other packages in Annex D.] (56) Add "(see 9.5)" to the end of E.2.2(14.1/3). (57) Swap paragraphs A.4.11(49/3) and A.4.11(50/3). (58) Modify A.16.1(28/3): "...an external file {(including directories and special files)} but is not a full name..." (59) Add the following array example to 5.5.2(14/3): -- Array component iterator example: for Element of Board loop -- See 3.6.1 Element := Element * 2.0; -- Double each element of Board, a two-dimensional array. end loop; (60) Replace 4.9(11/3) with: a membership test whose simple_expression is a static expression, and whose membership_choice_list consists only of membership_choices that are either static choice_expressions, static ranges, or subtype_marks that denote a static (scalar or string) subtype; (61) Replace A.18.10(173/3) with: Equivalent to Insert_Child (Container, Parent, No_Element, New_Item, Count). (62) Add "with Pack" to B.3(23/3). !discussion For (23), we copy the wording of 13.3(26.3/2). For (34), the commenter would have preferred wording closer to the Ada 2005 wording, something along the lines of: "For such an assignment, the result may be *built in place*, that is, directly in the target object and not by means of an anonymous object." Unfortunately, that's wrong with the model used by the Standard. The anonymous object always exists (even when built-in-place), it just is colocated with the target object and thus no copying is needed to assign it (this is called *mutation*). We had to adopt this (admittedly bizarre) model to deal with corner cases where it is possible to tell the differences between the target object and the anonymous object, which may have different types, tags, and finalization. For (36), the subphrases of 4.5.2(2/3) all bind to "determines whether or not a value", and "has accessibility level" makes more sense than "with accessibility level" with this lead-in. For (42), the original suggestion to use a bulleted list was not used as that would change this single paragraph into eight paragraphs. That would improve the wording a bit, but not enough to justify the complication of introducing seven additional paragraphs. For (44), the question was raised why the parameters in this package aren't lined up as in most language defined packages. That was not done here as it was not done in the parent System.Storage_Pools package, and it seemed important to be consistent with that package. Changing System.Storage_Pools to align the parameters seems wrong as it is not modified by Ada 2012. For (62), the editor strongly disagrees with this change. First, none of the Annex B packages should have any representation clauses. The critical requirement for these packages is B.3(42) and equivalent: these types match the representation of the appropriate C (or other language) compiler. The Ada representation MUST match that compiler, and the implementation needs to specify whatever representation is needed to match that compiler. Any language-defined representation simply interferes with that. So, no pack or other representation should be given in any of these packages. Second, this particular declaration also has a Component_Size clause. That clause is sufficient to specify the representation if we in fact wanted to do that. Indeed, specifying Pack here is almost certainly wrong. Even if an implementation takes advantage of 13.3(73/3) [which is unfriendly to the user by ignoring their explicit instructions], it is very unlikely that the exception given there would apply to this array (CHAR_BIT is almost certainly a "factor or multiple of the word size"). And in the extremely unlikely case that this is not true, the C compiler would certainly have used an unpacked representation for this array and the Pack would give the wrong representation. Thus, giving Pack on this declaration is both unnecessary and potentially harmful. Removing all of the Pack specifications is considered too much change at this point (a position that the editor does not disagree with). But there should be no problem with removing unnecessary, redundant or harmful specifications, such as this one. The original commenter -- and the full ARG which is forcing this change over the editor's objections -- are endorsing consistency over correctness, which is a completely silly position and one that the editor cannot agree with. !corrigendum 1(2) @drepl The language includes a complete facility for the support of real-time, concurrent programming. Errors can be signaled as exceptions and handled explicitly. The language also covers systems programming; this requires precise control over the representation of data and access to system-dependent properties. Finally, a predefined environment of standard packages is provided, including facilities for, among others, input-output, string manipulation, numeric elementary functions, and random number generation. @dby The language includes a complete facility for the support of real-time, concurrent programming. Errors can be signaled as exceptions and handled explicitly. The language also covers systems programming; this requires precise control over the representation of data and access to system-dependent properties. Finally, a predefined environment of standard packages is provided, including facilities for, among others, input-output, string manipulation, numeric elementary functions, random number generation, and definition and use of containers. !corrigendum 3.2.4(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 3.5(56/2) @dinsa An implementation may extend the Wide_Wide_Value, Wide_Value, Value, Wide_Wide_Image, Wide_Image, and Image attributes of a floating point type to support special values such as infinities and NaNs. @dinss An implementation may extend the Wide_Wide_Value, Wide_Value, and Value attributes of a character type to accept strings of the form "Hex_hhhhhhhh" (ignoring case) for any character (not just the ones for which Wide_Wide_Image would produce that form @emdash see 3.5.2), as well as three-character strings of the form "'@i'", where @i is any character, including nongraphic characters. !corrigendum 3.10.1(13) @dinsa @xindent<@s9<85 Within a @fa, an @fa and a corresponding @fa cannot be separated by an intervening body. This is because a type has to be completely defined before it is frozen, and a body freezes all types declared prior to it in the same @fa (see 13.14).>> @dinst @xindent<@s9<86 A @fa that denotes an object of an incomplete view is defined to be of a limited type. Hence, the target of an assignment statement cannot be of an incomplete view.>> !corrigendum 4.1.5(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 4.1.6(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 4.5.2(2) @drepl A @i, using @b or @b, determines whether or not a value belongs to a given subtype or range, or has a tag that identifies a type that is covered by a given type. Membership tests are allowed for all types. @dby A @i, using @b or @b, determines whether or not a value belongs to any given subtype or range, is equal to any given value, has a tag that identifies a type that is covered by a given type, or is convertible to and has accessibility level appropriate for a given access type. Membership tests are allowed for all types. !corrigendum 4.5.2(27) @dinsb For the evaluation of a membership test using @b whose @fa has a single @fa, the @fa and the @fa are evaluated in an arbitrary order; the result is the result of the individual membership test for the @fa. @dinst An @i is the membership test of a single @fa. !corrigendum 4.5.2(28) @drepl An @i yields the result True if: @dby An individual membership test yields the result True if: !corrigendum 4.5.2(30.2/2) @drepl @xbullet is not null.> @dby @xbullet is not null;> @xbullet is convertible to the tested type and its accessibility level is no deeper than that of the tested type; further, if the designated type of the tested type is tagged and the @fa is nonnull, the tag of the object designated by the value of the @fa is covered by the designated type of the tested type.> !corrigendum 4.5.7(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 4.8(3/1) @drepl The expected type for an @fa shall be a single access-to-object type with designated type @i such that either @i covers the type determined by the @fa of the @fa or @fa, or the expected type is anonymous and the determined type is @i'Class. @dby The expected type for an @fa shall be a single access-to-object type with designated type @i such that either @i covers the type determined by the @fa of the @fa or @fa, or the expected type is anonymous and the determined type is @i'Class. A @i@fa is expected to be of any type descended from Subpool_Handle, which is the type used to identify a subpool, declared in package System.Storage_Pools.Subpools (see 13.11.4). !corrigendum 4.9(11) @drepl @xbullet is a static expression, and whose @fa is a static range or whose @fa denotes a static (scalar or string) subtype;> @dby @xbullet is a static expression, and whose @fa consists only of @fas that are either static @fas, static @fas, or @fas that denote a static (scalar or string) subtype;> !corrigendum 4.9(33) @drepl A static expression is evaluated at compile time except when it is part of the right operand of a static short-circuit control form whose value is determined by its left operand. This evaluation is performed exactly, without performing Overflow_Checks. For a static expression that is evaluated: @dby @xbullet@fa of a @fa whose @i@fa is static and whose value is not covered by the corresponding @fa; or> A static expression is evaluated at compile time except when it is statically unevaluated. The compile-time evaluation of a static expression is performed exactly, without performing Overflow_Checks. For a static expression that is evaluated: !corrigendum 6.1.1(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 7.3(15) @drepl A declaration of a partial view and the corresponding @fa define two views of a single type. The declaration of a partial view together with the visible part define the operations that are available to outside program units; the declaration of the full view together with the private part define other operations whose direct use is possible only within the declarative region of the package itself. Moreover, within the scope of the declaration of the full view, the @i of the type are determined by the full view; in particular, within its scope, the full view determines the classes that include the type, which components, entries, and protected subprograms are visible, what attributes and other predefined operations are allowed, and whether the first subtype is static. See 7.3.1. @dby A declaration of a partial view and the corresponding @fa define two views of a single type. The declaration of a partial view together with the visible part define the operations that are available to outside program units; the declaration of the full view together with the private part define other operations whose direct use is possible only within the declarative region of the package itself. Moreover, within the scope of the declaration of the full view, the characteristics (see 3.4) of the type are determined by the full view; in particular, within its scope, the full view determines the classes that include the type, which components, entries, and protected subprograms are visible, what attributes and other predefined operations are allowed, and whether the first subtype is static. See 7.3.1. !corrigendum 7.3.1(5/1) @dinsa For example, an array type whose component type is limited private becomes nonlimited if the full view of the component type is nonlimited and visible at some later place immediately within the declarative region in which the array type is declared. In such a case, the predefined "=" operator is implicitly declared at that place, and assignment is allowed after that place. @dinss A type is a @i of the full view of some ancestor of its parent type only if the current view it has of its parent is a descendant of the full view of that ancestor. More generally, at any given place, a type is descended from the same view of an ancestor as that from which the current view of its parent is descended. This view determines what characteristics are inherited from the ancestor, and, for example, whether the type is considered to be a descendant of a record type, or a descendant only through record extensions of a more distant ancestor. It is possible for there to be places where a derived type is visibly a descendant of an ancestor type, but not a descendant of even a partial view of the ancestor type, because the parent of the derived type is not visibly a descendant of the ancestor. In this case, the derived type inherits no characteristics from that ancestor, but nevertheless is within the derivation class of the ancestor for the purposes of type conversion, the "covers" relationship, and matching against a formal derived type. In this case the derived type is considered to be a @i of an incomplete view of the ancestor. !corrigendum 7.3.2(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 7.4(2) @drepl A @i is an @fa with the reserved word @b but no initialization expression. The constant declared by a deferred constant declaration is called a @i. A deferred constant declaration requires a completion, which shall be a full constant declaration (called the @i of the deferred constant), or a @fa Import (see Annex B). @dby A @i is an @fa with the reserved word @b but no initialization expression. The constant declared by a deferred constant declaration is called a @i. Unless the Import aspect (see B.1) is True for a deferred constant declaration, the deferred constant declaration requires a completion, which shall be a full constant declaration (called the @i of the deferred constant). !corrigendum 7.6(17/2) @dinsa [A placeholder to cause a conflict; the real wording is found in the conflict file.] @dinst The real text is not here. !corrigendum 7.6.1(13/2) @drepl The master of an object is the master enclosing its creation whose accessibility level (see 3.10.2) is equal to that of the object. @dby The master of an object is the master enclosing its creation whose accessibility level (see 3.10.2) is equal to that of the object, except in the case of an anonymous object representing the result of an @fa or function call. If such an anonymous object is part of the result of evaluating the actual parameter expression for an explicitly aliased parameter of a function call, the master of the object is the innermost master enclosing the evaluation of the @fa or function call, excluding the @fa or function call itself. Otherwise, the master of such an anonymous object is the innermost master enclosing the evaluation of the @fa or function call, which may be the @fa or function call itself. !corrigendum 9.6.1(42/2) @drepl @xindent @dby @xindent !corrigendum 13.3(38) @drepl @s9<5 A @fa, Component_Size clause, or a @fa Pack can override a specified Alignment.> @dby @s9<5 A @fa, Component_Size clause, or specifying the Pack aspect as True can override a specified Alignment.> !corrigendum 13.3(65) @ddel [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 13.11(21) @Comment{This is a partial change, the entire change is found in the conflict file.} @dinsa If Storage_Pool is specified for an access type, then if Allocate can satisfy the request, it should allocate a contiguous block of memory, and return the address of the first storage element in Storage_Address. The block should contain Size_In_Storage_Elements storage elements, and should be aligned according to Alignment. The allocated storage should not be used for any other purpose while the pool element remains in existence. If the request cannot be satisfied, then Allocate should propagate an exception (such as Storage_Error). If Allocate behaves in any other manner, then the program execution is erroneous. @dinss @s8<@i> For each of the calls of Allocate described above, @i

(equivalent to @i'Storage_Pool) is passed as the Pool parameter. The Size_In_Storage_Elements parameter indicates the number of storage elements to be allocated, and is no more than @i'Max_Size_In_Storage_Elements, where @i is the designated subtype of @i. The Alignment parameter is a nonzero integral multiple of @i'Alignment if @i is a specific type, and otherwise is a nonzero integral multiple of the alignment of the specific type identified by the tag of the object being created; it is unspecified if there is no such value. The Alignment parameter is no more than @i'Max_Alignment_For_Allocation. The result returned in the Storage_Address parameter is used as the address of the allocated storage, which is a contiguous block of memory of Size_In_Storage_Elements storage elements. Any exception propagated by Allocate is propagated by the construct that contained the call. !corrigendum 13.11.4(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum 13.12(7/2) @ddel The set of restrictions is implementation defined. !corrigendum 13.12(9) @dinsb An implementation may place limitations on the values of the @fa that are supported, and limitations on the supported combinations of restrictions. The consequences of violating such limitations are implementation defined. @dinst An implementation may provide implementation-defined restrictions; the identifier for an implementation-defined restriction shall differ from those of the language-defined restrictions. !corrigendum 13.12(9.2/1) @dinsa Whenever enforcement of a restriction is not required prior to execution, an implementation may nevertheless enforce the restriction prior to execution of a partition to which the restriction applies, provided that every execution of the partition would violate the restriction. @dinst An implementation may provide implementation-defined usage-profiles; the identifier for an implementation-defined usage profile shall differ from those of the language-defined usage profiles. !corrigendum 13.12.1(2/2) @dinsa @xhang<@xterm There are no implementation-defined attributes. This restriction applies only to the current compilation or environment, not the entire partition.> @dinss @xhang<@xterm There are no usage names that denote declarations with implementation-defined identifiers that occur within language-defined packages or instances of language-defined generic packages. Such identifiers can arise as follows:> !corrigendum 13.13.2(26) @drepl @xbullet is an array type, S'Output first writes the bounds, and S'Input first reads the bounds. If @i has discriminants without defaults, S'Output first writes the discriminants (using S'Write for each), and S'Input first reads the discriminants (using S'Read for each).> @dby @xbullet is an array type, S'Output first writes the bounds, and S'Input first reads the bounds. If @i has discriminants without defaults, S'Output first writes the discriminants (using the Write attribute of the discriminant type for each), and S'Input first reads the discriminants (using the Read attribute of the discriminant type for each).> !corrigendum A.3.5(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.4.11(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.16.1(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.17(19/2) @drepl If the external execution environment supports environment variables, then Clear deletes all existing environment variable with the given name. Otherwise Program_Error is propagated. @dby If the external execution environment supports environment variables, then Clear deletes all existing environment variables with the given name. Otherwise, Program_Error is propagated. !corrigendum A.18.2(147/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.2(230/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.3(86/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.3(144/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.4(41/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.5(61/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.6(94/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.7(36/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.7(96/2) @dinsa Force a conflict; the real text is found in the conflict file. @dinst Nothing. !corrigendum A.18.8(85/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.9(113/2) @drepl Force a conflict; the real text is found in the conflict file. @dby Nothing. !corrigendum A.18.10(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.18(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.21(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.22(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.23(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum A.18.24(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum B.1(1) @drepl A @fa Import is used to import an entity defined in a foreign language into an Ada program, thus allowing a foreign-language subprogram to be called from Ada, or a foreign-language variable to be accessed from Ada. In contrast, a @fa Export is used to export an Ada entity to a foreign language, thus allowing an Ada subprogram to be called from a foreign language, or an Ada object to be accessed from a foreign language. The @fas Import and Export are intended primarily for objects and subprograms, although implementations are allowed to support other entities. @dby An @i aspect is a representation aspect that is one of the aspects Import, Export, Link_Name, External_Name, or Convention. Specifying the Import aspect to have the value True is used to import an entity defined in a foreign language into an Ada program, thus allowing a foreign-language subprogram to be called from Ada, or a foreign-language variable to be accessed from Ada. In contrast, specifying the Export aspect to have the value True is used to export an Ada entity to a foreign language, thus allowing an Ada subprogram to be called from a foreign language, or an Ada object to be accessed from a foreign language. The Import and Export aspects are intended primarily for objects and subprograms, although implementations are allowed to support other entities. The Link_Name and External_Name aspects are used to specify the link name and external name, respectively, to be used to identify imported or exported entities in the external environment. !corrigendum B.1(40) @drepl Automatic elaboration of preelaborated packages should be provided when @fa Export is supported. @dby Automatic elaboration of preelaborated packages should be provided when specifying the Export aspect as True is supported. !corrigendum B.1(51) @drepl @xcode<@b Fortran_Library @b @b Sqrt (X : Float) @b Float; @b Exp (X : Float) @b Float; @b @b Import(Fortran, Sqrt); @b Import(Fortran, Exp); @b Fortran_Library;> @dby @xcode<@b Fortran_Library @b @b Sqrt (X : Float) @b Float @b Import =@> True, Convention =@> Fortran; @b Matrix @b (Natural @b <@>, Natural @b <@>) @b Float @b Convention =@> Fortran; @b Invert (M : Matrix) @b Matrix @b Import =@> True, Convention =@> Fortran; @b Fortran_Library;> !comment %% B.3(23) needs changes here (there was no original change, so there is none here either). !corrigendum B.3.3(1/2) @drepl A pragma Unchecked_Union specifies an interface correspondence between a given discriminated type and some C union. The pragma specifies that the associated type shall be given a representation that leaves no space for its discriminant(s). @dby Specifying aspect Unchecked_Union to have the value True defines an interface correspondence between a given discriminated type and some C union. The aspect requires that the associated type shall be given a representation that allocates no space for its discriminant(s). !corrigendum D.2.4(11/2) @drepl Since implementations are allowed to round all ceiling priorities in subrange System.Priority to System.Priority'Last (see D.3), an implementation may allow a task to execute within a protected object without raising its active priority provided the associated protected unit does not contain pragma Interrupt_Priority, Interrupt_Handler, or Attach_Handler. @dby Since implementations are allowed to round all ceiling priorities in subrange System.Priority to System.Priority'Last (see D.3), an implementation may allow a task of a partition using the Non_Premptive_FIFO_Within_Priorities policy to execute within a protected object without raising its active priority provided the associated protected unit does not contain any subprograms with aspects Interrupt_Handler or Attach_Handler specified, nor does the unit have aspect Interrupt_Priority specified. When the locking policy (see D.3) is Ceiling_Locking, an implementation taking advantage of this permission shall ensure that a call to Yield_to_Higher that occurs within a protected action uses the ceiling priority of the protected object (rather than the active priority of the task) when determining whether to preempt the task. !corrigendum D.10(10) @dinsa Program_Error is raised upon calling Suspend_Until_True if another task is already waiting on that suspension object. Suspend_Until_True is a potentially blocking operation (see 9.5.1). @dinst The procedure Suspend_Until_True_And_Set_Deadline blocks the calling task until the state of the object S is True; at that point the task becomes ready with a deadline of Ada.Real_Time.Clock + TS, and the state of the object becomes False. Program_Error is raised upon calling Suspend_Until_True_And_Set_Deadline if another task is already waiting on that suspension object. Suspend_Until_True_And_Set_Deadline is a potentially blocking operation. !corrigendum D.14(11/2) @drepl The @i or CPU time of a given task is defined as the time spent by the system executing that task, including the time spent executing run-time or system services on its behalf. The mechanism used to measure execution time is implementation defined. It is implementation defined which task, if any, is charged the execution time that is consumed by interrupt handlers and run-time services on behalf of the system. @dby The @i or CPU time of a given task is defined as the time spent by the system executing that task, including the time spent executing run-time or system services on its behalf. The mechanism used to measure execution time is implementation defined. The Boolean constant Interrupt_Clocks_Supported is set to True if the implementation separately accounts for the execution time of interrupt handlers. If it is set to False it is implementation defined which task, if any, is charged the execution time that is consumed by interrupt handlers. The Boolean constant Separate_Interrupt_Clocks_Supported is set to True if the implementation separately accounts for the execution time of individual interrupt handlers (see D.14.3). !corrigendum D.16.1(0) @dinsc [A placeholder to cause a conflict; the real wording is found in the conflict file.] !corrigendum E.2(5) @drepl The various categories of library units and the associated restrictions are described in this clause and its subclauses. The categories are related hierarchically in that the library units of one category can depend semantically only on library units of that category or an earlier one, except that the body of a remote types or remote call interface library unit is unrestricted. @dby The various categories of library units and the associated restrictions are described in this clause and its subclauses. The categories are related hierarchically in that the library units of one category can depend semantically only on library units of that category or an earlier one in the hierarchy, except that the body of a remote types or remote call interface library unit is unrestricted, the declaration of a remote types or remote call interface library unit may depend on preelaborated normal library units that are mentioned only in private with clauses, and all categories can depend on limited views. !corrigendum E.2(6) @drepl The overall hierarchy (including declared pure) is as follows: @dby The overall hierarchy (including declared pure) is as follows, with a lower-numbered category being "earlier in the hierarchy" in the sense of the previous paragraph: !corrigendum E.2.2(14/2) @dinsa @xbullet @dinst @xbullet is Optional (see 9.5);> !ACATS Test None needed. !ASIS No change needed. !appendix From: Steve Baird Sent: Friday, March 11, 2011 7:06 PM [This message was misplaced which is why it is getting handled in this AI; only the relevant part is included here.] While looking at this, I did notice a minor wording issue. In 13.13.2(26), the parenthesized wording eems wrong: If T has discriminants without defaults, S'Output first writes the discriminants (using S'Write for each), and S'Input first reads the discriminants (using S'Read for each). S is a discriminated subtype. We are using S'Write and S'Read to write/read single discriminant values? Probably "using S'Write" should be replaced with something like "using the Write attribute of each dicriminant type", and similarly for Read. **************************************************************** From: Bob Duff Sent: Wednesday, September 15, 2010 4:39 PM [This thread was unintentionally ignored and just now has been rediscovered, which is why it is getting handled in this AI - Editor.] AI05-0193-1: Alignment of allocators says: The Alignment parameter is at least D'Alignment if D is a specific type, and otherwise is at least the alignment of the specific type identified by the tag of the object being created. The Alignment parameter is no more than D'Max_Alignment_For_Allocation. Shouldn't it say it's "equal to or stricter than D'Alignment"? That is, equal to D'Alignment, or some positive integer multiple thereof. Because if D'Alignment is 4, you don't want to pass Alignment => 5 to Allocate. 4, 8, or 16 should be OK. 12 is weird, but still OK, I guess. **************************************************************** From: Robert Dewar Sent: Wednesday, September 15, 2010 4:41 PM Only powers of 2 make sense for alignments anyway, so in practice greater/less than mean the same as multiple/factor **************************************************************** From: Tucker Taft Sent: Wednesday, September 15, 2010 5:05 PM I agree "stricter" is more correct. Do we use that term elsewhere? **************************************************************** From: Bob Duff Sent: Wednesday, September 15, 2010 5:39 PM > I agree "stricter" is more correct. > Do we use that term elsewhere? Only in the AARM, as far as I know. I don't think we need to have a formal definition of "stricter" in order to use it in the RM. It's clear what it means. Or we can just leave it alone, and trust implementers to never pass Alignment=>5 or the like. Re: Robert's comment: I would have been happy with a rule saying Alignment must be a power of 2. I can't imagine any hardware (past, present, or future) where anything else would make sense. I'd be interested in hearing of counter-examples, if such exist[ed]! **************************************************************** From: Robert Dewar Sent: Wednesday, September 15, 2010 6:11 PM Certainly GNAT requires alignments to be a power of 2 **************************************************************** From: Tucker Taft Sent: Wednesday, September 15, 2010 6:09 PM > I don't think we need to have a formal definition of "stricter" in > order to use it in the RM. > It's clear what it means. ... What I was really asking was how do we require that one alignment be stricter than another alignment in other places in the manual. I just looked in the section on the 'Alignment attribute, and we always talk in terms of one alignment being a multiple of another alignment. So I think we should use that terminology here, rather than "greater" or "stricter". **************************************************************** From: Bob Duff Sent: Wednesday, September 15, 2010 6:31 PM OK, that makes sense. [Randy will no doubt include this in the appendix of the AI in a way that makes the referent of "that" in "that makes sense" unclear. Sigh.] [Editor's note: I did my best to follow his instructions. :-) If you the reader are really confused, the preceeding message is the referent.] **************************************************************** From: Randy Brukardt Sent: Monday, September 27, 2010 5:59 PM Forget my filing system: my new phone just showed "OK, that makes sense" with all of the quoted stuff eliminated. So I didn't find out what you meant until I looked at it here in the office. Probably best to write a few more words (but that's not fun when answering from a phone). **************************************************************** From: Bob Duff Sent: Monday, September 27, 2010 6:19 PM Reading e-mail on a phone is something I would never consider doing. I realize that makes me a luddite. ;-) But seriously, I don't think you should be vigorously trying to keep the !appendix sections small. Over-quoting is a sin, but underquoting is a worse sin. I really find it hard to follow the conversation when I can't tell what someone is replying to. And I was deliberately yanking your chain when I wrote just "OK, that makes sense.", which is incomprehensible without context. ;-) **************************************************************** From: Randy Brukardt Sent: Friday, January 13, 2012 12:50 AM Steve's review includes: > In 13.12(7/2), we have > The set of restrictions is implementation defined. > > Do we need a similar rule for usage profiles somewhere? This rule seems wrong for restrictions, so I don't want one like it for profiles. I don't know why it is under "Static Semantics". For attributes and pragmas, the similar rule is an "Implementation Permission". And the wording above seems to allow the implementation to not implement language-defined restrictions (it doesn't say anything about "adding" restrictions). I doubt that is what we want! So I'd suggest something like Implementation Permissions An implementation may provide implementation-defined restrictions and usage profiles. Or possibly two sentences (one before paragraph 9 for restrictions, and the other after paragraph 14 for profiles). And delete the existing rule. What does everyone else think? **************************************************************** From: Tucker Taft Sent: Friday, January 13, 2012 8:58 AM I agree with your approach. **************************************************************** From: Steve Baird Sent: Friday, January 13, 2012 11:19 AM Ditto. Specifically, I agree with your second approach (consistent treatment of restrictions and profiles). **************************************************************** From: Tullio Vardanega Sent: Friday, January 13, 2012 11:30 AM I also agree with the second of Randy's suggested approaches. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 11:36 AM >> What does everyone else think? Do we want to add but may not extend or modify any of the language defined restrictions or usage profiles. (same rule as for pragmas, perhaps implied, but I think useful to make it explicit). **************************************************************** From: Tullio Vardanega Sent: Friday, January 13, 2012 11:47 AM Yes, it does sound like a useful precaution to me. **************************************************************** From: Tucker Taft Sent: Friday, January 13, 2012 11:47 AM > Do we want to add > > but may not extend or modify any of the language defined restrictions > or usage profiles. We may not use "may not" in ISO standards. Shall not we all use "shall not" instead? ;-) > (same rule as for pragmas, perhaps implied, but I think useful to make > it explicit). Does seem a bit redundant, since we disallow any of this sort of thing in general. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 11:51 AM Well it always seems very odd to me to allow new pragmas, but not impl added extensions to existing pragmas and results in awkward work arounds, so I think this is worth saying. in impl advice we try to be clear rather than non-redundantly formal :-) **************************************************************** From: Erhard Ploedereder Sent: Friday, January 13, 2012 1:11 PM We shall use shall not, so the sentence shall read: "but shall not extend or modify any of the language defined restrictions or usage profiles." Shall we agree? ;-) **************************************************************** From: Randy Brukardt Sent: Friday, January 13, 2012 1:37 PM ... > Do we want to add > > but may not extend or modify any of the language defined restrictions > or usage profiles. > > (same rule as for pragmas, perhaps implied, but I think useful to make > it explicit). There is no such rule for pragmas (I checked these before I sent my original message). The only thing that is said 2.9(14) is that an implementation-defined pragma has a different name, which would have said here: "the identifier for an implementation-defined restriction shall differ from those of the language-defined restrictions" but this is nonsense for restrictions because the names have to be unique anyway. There is nothing about "extend or modify", presumably because that goes without saying anyway. An implementation is allowed to *add* pragmas, attributes, aspects, and restrictions, but is it *never* allowed to change a language-defined one. Even if the item is defined in an annex that you're not implementing. See 1.1.3, and especially 1.1.3(17/3). I could be convinced to add the above text (to match pragmas and attributes), but I would be against saying any more. I can't imagine why people would have to be told not to extend restrictions and not told the same thing about pragmas. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 1:51 PM ... > There is no such rule for pragmas (I checked these before I sent my > original message). The only thing that is said 2.9(14) is that an > implementation-defined pragma has a different name, which would have > said > here: I think there is dwefinitely intended to be a rule that you can't modify or extend language defined pragmas. Do you really believe that is not the case, because if so, there are several places we would be delighted to extend existing language pragmas in GNAT :-) > There is nothing about "extend or modify", presumably because that > goes without saying anyway. An implementation is allowed to *add* > pragmas, attributes, aspects, and restrictions, but is it *never* > allowed to change a language-defined one. Even if the item is defined > in an annex that you're not implementing. See 1.1.3, and especially 1.1.3(17/3). OK, now I am confused, you said there was no such rule for pragmas, and then you say it "goes without saying", not clear to me. It would seem quite reasonable to say that implementations must intepret language defined pragmas as defined in the RM, but are allowed to e.g. add arguments. > I could be convinced to add the above text (to match pragmas and > attributes), but I would be against saying any more. I can't imagine > why people would have to be told not to extend restrictions and not > told the same thing about pragmas. I think they should be told that for pragmas, and "goes without saying" is not exactly a recognized principle in defining language rules. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 1:56 PM By the way, for my taste I see no difference between an implementation defined aspect that will blow up any compiler not recognizing it, and an extension to a language defined aspect that will blow up any compiler not recognzing it. **************************************************************** From: Brad Moore Sent: Friday, January 13, 2012 2:25 PM > I think there is dwefinitely intended to be a rule that you can't > modify or extend language defined pragmas. Do you really believe that > is not the case, because if so, there are several places we would be > delighted to extend existing language pragmas in GNAT :-) I agree with everyone else, that the second part of Randy's is a better approach. I also agree with Robert, that it is good to be clear about altering/extending language defined pragmas. I don't think it hurts to be more precise, if we are making a change in this area anyway. **************************************************************** From: Randy Brukardt Sent: Friday, January 13, 2012 2:46 PM > I think there is dwefinitely intended to be a rule that you can't > modify or extend language defined pragmas. Do you really believe that > is not the case, because if so, there are several places we would be > delighted to extend existing language pragmas in GNAT :-) There is no such rule, because there is a rule that you can't modify or extend *anything* in Ada. So why mention this specifically for pragmas? (And not for attributes or if statements or subprograms?) > > There is nothing about "extend or modify", presumably because that > > goes without saying anyway. An implementation is allowed to *add* > > pragmas, attributes, aspects, and restrictions, but is it *never* > > allowed to change a language-defined one. Even if the item is > > defined in an annex that you're not implementing. See 1.1.3, and > > especially 1.1.3(17/3). > > OK, now I am confused, you said there was no such rule for pragmas, > and then you say it "goes without saying", not clear to me. It would > seem quite reasonable to say that implementations must intepret > language defined pragmas as defined in the RM, but are allowed to e.g. > add arguments. You missed my point. There is a blanket rule in 1.1.3 that you can't modify or extend anything in Ada. (It doesn't say that in those exact words, which is why I didn't give a paragraph reference, but it's clear if you read the entire section that that is the intent.) So pragmas don't say this explicitly, because it is true of everything in the Standard; it goes without saying it (other than in the introduction of the Standard). > > I could be convinced to add the above text (to match pragmas and > > attributes), but I would be against saying any more. I can't imagine > > why people would have to be told not to extend restrictions and not > > told the same thing about pragmas. > > I think they should be told that for pragmas, and "goes without saying" > is not exactly a recognized principle in defining language rules. OK, but no one has ever (previously) complained that there isn't enough text in the pragma section, and I think this is a dangerous precedent to set. Once you mention that something cannot be "modified or extended", that suggests that other things that don't say that might be able to be extended. So then you have to add that wording to many (or all) places where implementation-defined behavior is allowed. So I'm still against (normatively) repeating something that is *always* true in specific places as if there is some difference in those specific places. I could be convinced that a note would be worthwhile -- but given that this is unchanged since Ada 95, I'm very dubious that there is any need. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 2:56 PM > There is no such rule, because there is a rule that you can't modify > or extend *anything* in Ada. So why mention this specifically for > pragmas? (And not for attributes or if statements or subprograms?) There is no such rule! And you can extend something in Ada, notably the set of pragmas, or the set of aspects, or even the syntax for aspects. I think it is not obvious at all that you can add a pragma, but not add a parameter to an existing pragma. Or add an attribute, but not extend the applicability of an existing attribute. I always hate arguments where we have A: I think X is unclear, we should clarify it B; I think it's clear, so I disagree But A is simply saying that there are some people who find it unclear and that's a pretty strong argument that it is worth clarifying. B's argument does not contradict this, there is a difference between "there exists" and "for all". **************************************************************** From: Tucker Taft Sent: Friday, January 13, 2012 3:15 PM I tend to agree with Randy on this one. I see no strong reason to add verbiage beyond what is already in paragraph 1.1.3(17/3). Here are some of the relevant paragraphs from 1.1.3: 1 A conforming implementation shall: ... 6 Contain no variations except those explicitly permitted by this International Standard, or those that are impossible or impractical to avoid given the implementation's execution environment; 7 Specify all such variations in the manner prescribed by this International Standard. ... 16 An implementation that conforms to this Standard shall support each capability required by the core language as specified. In addition, an implementation that conforms to this Standard may conform to one or more Specialized Needs Annexes (or to none). Conformance to a Specialized Needs Annex means that each capability required by the Annex is provided as specified. 17/3 An implementation conforming to this International Standard may provide additional aspects, attributes, library units, and pragmas. However, it shall not provide any aspect, attribute, library unit, or pragma having the same name as an aspect, attribute, library unit, or pragma (respectively) specified in a Specialized Needs Annex unless the provided construct is either as specified in the Specialized Needs Annex or is more limited in capability than that required by the Annex. A program that attempts to use an unsupported capability of an Annex shall either be identified by the implementation before run time or shall raise an exception at run time. **************************************************************** From: Bob Duff Sent: Friday, January 13, 2012 3:24 PM > I always hate arguments where we have > > A: I think X is unclear, we should clarify it > > B; I think it's clear, so I disagree Sure, but if B explains why it's clear, then A can become convinced. Hopefully A isn't sticking his fingers in his ears and shouting "La La La La". ;-) But I don't think we should even be discussing this. Our current job is to get the Ada 2012 changes right. If something about pragmas is unclear, it's been unclear since 1983, and we're not in the business of fixing such things right now. **************************************************************** From: Brad Moore Sent: Friday, January 13, 2012 3:57 PM > Sure, but if B explains why it's clear, then A can become convinced. > Hopefully A isn't sticking his fingers in his ears and shouting "La La > La La". ;-) As an example of this, Tuckers previous email and Randy's latest arguments have cause me to join the rank of the convinced. I think the original suggested change (Randy's part 2) is fine without having to mention disallowing modification or extending language defined pragmas. **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 4:34 PM Please recall that my initial concern was with aspects, we allow aspects to be added, and leave it completely free what the syntax will be, but I guess we don't want to allow a new aspect whose specified syntax looks like an extension of an existing aspect :-) **************************************************************** From: Robert Dewar Sent: Friday, January 13, 2012 4:38 PM But no big deal, I really think that all these discussions of details in wording of the RM don't matter much :-) **************************************************************** From: Bob Duff Sent: Friday, January 13, 2012 5:16 PM > > Please recall that my initial concern was with aspects, we allow > > aspects to be added, and leave it completely free what the syntax > > will be, but I guess we don't want to allow a new aspect whose > > specified syntax looks like an extension of an existing aspect :-) Oh, OK, I suppose that should be clarified. I haven't read the whole thread, in which case I'd normally keep my mouth shut, but I just wanted to avoid a long discussion of some Ada 83 rules that may or may not be clear. I'll try to comment about the aspects after reading the whole thread. > But no big deal, I really think that all these discussions of details > in wording of the RM don't matter much :-) Yes, I generally agree. **************************************************************** From: Randy Brukardt Sent: Friday, January 13, 2012 5:34 PM > > > Please recall that my initial concern was with aspects, we allow > > > aspects to be added, and leave it completely free what the syntax > > > will be, but I guess we don't want to allow a new aspect whose > > > specified syntax looks like an extension of an existing aspect :-) > > Oh, OK, I suppose that should be clarified. Well, we originally were talking about "profiles" and "restrictions"; nothing to do with aspects. I don't recall anyone ever saying anything about the wording of aspects (and I know I've not looked at it lately). The original question from Steve is whether we needed a rule allowing implementation-defined profiles, and the answer to that is clearly yes. But I then complained about the Ada 95 rule for restrictions (which in the same clause, so it's relevant for consistency reasons), which appears to allow anything for those (including not implementing language-defined ones; it's nice to know that the non-existent Janus/Ada implementation of restrictions is conforming :-). I should probably have just done the right thing and let people complain about it in Houston. An attempt to get confirmation that my understanding is right has led off into a huge waste of time for everyone involved (and I've only gotten a weak confirmation of my original question). So, please don't waste *your* time reading the whole thread. **************************************************************** From: Randy Brukardt Sent: Friday, January 27, 2012 1:53 AM A couple of weeks ago, I responded to one of Steve's comments thusly: > > 13.11(21.5/3) says > > The Alignment parameter is at least D'Alignment if D is a > > specific type, ... > > > > It does seem odd that if D'Alignment is 4, then this would allow > > passing in a value of 5. > > > > We may have already talked about this one and decided to ignore it. > > I vaguely remember such a discussion, but it doesn't seem to appear in > the filed e-mail (or we decided to ignore it). > > It doesn't seem too critical; it sounds hard to nail this down > perfectly. (I can't think of a reason to support an alignment of, say > 6, but I wouldn't be surprised of someone had a reason on some unusual > machine. So requiring only powers-of-two along wouldn't seem > appropriate to me.) I just ran across the old e-mail discussion (from September 2010!). Tucker suggested using "multiple" as that is what 13.3 uses when comparing to alignments. (Actually, the wording is "nonzero integral multiple".) It seems that your editor was supposed to make this change, but it got lost in a blizzard of mail on other topics. So the wording should be: The Alignment parameter is a nonzero integral multiple of D'Alignment if D is a specific type, and otherwise is a nonzero integral multiple the alignment of the specific type identified by the tag of the object being created. Please speak up if you (or anyone) disagrees for some reason. (It's been a year and a half; everyone should have changed their minds by now... :-) **************************************************************** From: Tucker Taft Sent: Friday, January 27, 2012 7:14 AM > ... > The Alignment parameter is a nonzero integral multiple of D'Alignment > if D is a specific type, and otherwise is a nonzero integral multiple > the "of" -------^^ > alignment of the specific type identified by the tag of the object > being created. **************************************************************** From: Steve Baird Sent: Friday, January 27, 2012 11:36 AM ... > The Alignment parameter is a nonzero integral multiple of D'Alignment > if D is a specific type, and otherwise is a nonzero integral multiple > of the alignment of the specific type identified by the tag of the > object being created. A nonzero integral multiple of D'Alignment may be difficult to find in the case where D'Alignment = 0. **************************************************************** From: Dan Eilers Sent: Friday, January 27, 2012 11:50 AM Depends on how you hypenate it. A nonzero-integral-multiple of D'Alignment is easier to find than a nonzero integral-multiple-of-D'Alignment. **************************************************************** From: Randy Brukardt Sent: Friday, January 27, 2012 2:42 PM > A nonzero integral multiple of D'Alignment may be difficult to find in > the case where D'Alignment = 0. True enough. But I don't think we want the Alignment parameter to be zero even in that case, so we need the "nonzero integral" part anyway. And it really doesn't make sense for a subtype (as opposed to an object) to have an alignment of zero; I can't imagine a why a compiler would want to bit-pack stand-alone objects. So, in the interest of not making this even more complicated, I'd suggest just adding a To-Be-Honest: If D'Alignment is zero, then it is not strictly possible to have a "nonzero integral multiple" of the alignment; in that case, any nonzero alignment may be passed. I don't see any decent way to talk about the other case of alignment in this note, either. The only other practical option that I see is to back out the change and return to the original "at least" wording (it's at least not wrong in obscure cases, it just allows too much). It's not practical put a condition on the text as is found in 13.3(26.3/2), because that requires referring to the alignment of the type to be passed twice, and I can't find a reasonable way to talk about that once (as in the note above), much less twice. So, please tell me whether: (A) fix this with a TBH; (B) revert to the original wording; or (C) propose some wording that actually works. [Bob being the person who originally wanted a change here, he is not allowed to chose (B). :-)] **************************************************************** From: Steve Baird Sent: Friday, January 27, 2012 6:40 PM Append to previous wording: The value of the Alignment parameter is unspecified if D'Alignment is zero. I suppose that to be precise we should handle the oddball case first and then begin the normal case with "Otherwise, ". Let's not. **************************************************************** From: Randy Brukardt Sent: Friday, January 27, 2012 6:53 PM My objection to that is that it doesn't cover the other zero case, that is when "the alignment of the specific type identified by the tag of the object being created" is zero. That is such a mouthful that repeating it is horrible. We'd have to factor it out somehow. Try: Given that the alignment A for a call to Allocate is D'Alignment if D is a specific type, and otherwise is a nonzero integral multiple of the alignment of the specific type identified by the tag of the object being created, the Alignment parameter is a nonzero integral multiple of A if A is nonzero, and is unspecified otherwise. Or something like that. But I'm really dubious that it is worth this much hassle to deal with a case that should never happen anyway. (Why do we even allow subtypes to have a zero alignment? It's only meaningful for objects.) **************************************************************** From: Steve Baird Sent: Friday, January 27, 2012 7:12 PM How about The value of the Alignment parameter is unspecified if D'Alignment (or the alignment of the corresponding specific type if D is classwide) is zero. ? **************************************************************** From: Robert Dewar Sent: Friday, January 27, 2012 8:20 PM How could a classwide type possibly have an alignment of zero? **************************************************************** From: Randy Brukardt Sent: Friday, January 27, 2012 8:43 PM It's not talking about the alignment of the class-wide type, but rather the alignment of some specific type that belongs to it. And the language allows such an alignment to be specified, and a compiler could support it, and the wording needs to make sense if that happens. Now, does it make *sense* to specify such an alignment? No. Indeed, I don't think it makes sense ever to have a zero alignment on any subtype (as opposed to an object), because the requirements for independence prevent any sort of bit packing of objects or components unless it is explicitly requested by a rep item on that object or (type containing that) component. Nevertheless, it is allowed and the wording needs to make sense. To answer Steve, I don't much like the two sentence solution, because you have two sentences that give conflicting information about a single value. It's OK to have two sentences if they are disjoint cases, but that's not true here. **************************************************************** From: Robert Dewar Sent: Friday, January 27, 2012 8:51 PM > Now, does it make *sense* to specify such an alignment? No. Indeed, I > don't think it makes sense ever to have a zero alignment on any > subtype (as opposed to an object), because the requirements for > independence prevent any sort of bit packing of objects or components > unless it is explicitly requested by a rep item on that object or (type containing > that) component. Nevertheless, it is allowed and the wording needs to make sense. Well tagged types in particular are always going in practice to have at least pointer alignment :-) **************************************************************** From: Randy Brukardt Sent: Friday, January 27, 2012 9:05 PM Right. Alignment zero can really only make sense for discrete types, and even then it seems dubious for a subtype. (You'll almost always use more code than you would save in memory, and the independence requirements make it unlikely anyway.) It makes sense that the alignment of an object can be 0 (which it is the component of a packed composite type), but I can't quite see any case when you should specify it to be zero (and I don't think would ever be zero by default for a subtype). Anyway, what we're talking about is the definition of what gets passed to a storage pool. I don't think it makes much sense to ask a pool for unaligned memory, so I'm dubious about the "unspecified" part of this. But I suppose we don't want to require something that we didn't require in the past, and it appears that it is OK to pass 0 to a pool. Why, I don't know. **************************************************************** From: Jean-Pierre Rosen Sent: Saturday, January 28, 2012 1:33 AM > (C) propose some wording that actually works. The Alignment parameter is a nonzero integral multiple of D'Alignment (unless D'Alignment is zero) ... The Alignment parameter is an integral nonzero multiple of D'Alignment... The Alignment parameter is D'Alignment or an nonzero integral multiple thereof... **************************************************************** From: Alan Burns Sent: Monday, September 19, 2011 4:51 AM We have just held IRTAW - lots of interesting stuff for post Ada2012! But a couple of 'editorial' issues were noted with regard to D.16.1 package System.Multiprocessors.Dispatching_Domain has pragma Preelaborate. But it also withs Ada.Real-Time that does not have this pragma. This seems to be wrong. ... [Rest omitted here, in AI05-0278-1.] **************************************************************** !topic Another 3.2.4(12) nitpick !reference RM12 3.2.4(12/3) !from Adam Beneschan 11-11-14 !discussion One other thing about 3.4.2(12): a call to a predefined boolean logical operator, where both operands are predicate-static; ... Since this says "logical operator", it would appear to exclude the short-circuit control forms; the wording of 4.5.1 means that "and then" and "or else" aren't operators. Is there a valid reason for excluding them in static predicates? The way the rest of the section on static predicates is worded, I believe that there is no way it could possibly make a semantic difference whether "and" or "and then" is used, and similarly "or" vs. "or else". However, I suspect there are Ada programmers who habitually use the short-circuit forms (in my experience, there are very few circumstances where it's *necessary* to use the logical operator form on boolean operands), and it seems potentially frustrating to those programmers to force them to go against their habit when there doesn't seem to be a good reason for requiring this. **************************************************************** From: Bob Duff Sent: Tuesday, November 15, 2011 9:11 AM ... > Since this says "logical operator", it would appear to exclude the > short-circuit control forms; the wording of 4.5.1 means that "and > then" and "or else" aren't operators. Is there a valid reason for > excluding them in static predicates? Excluding the short-circuits was deliberate. The AI makes that clear. I don't remember whether the AI gives any compelling reason -- probably just that they're not needed. (In general, when asking "why" the 2012 RM is the way it is, it's a good idea to look at the AI's, because not all of the rationale has made it into AARM annotations. For this particular AI, that's due to laziness on my part.) >...The way the rest of the section > on static predicates is worded, I believe that there is no way it >could possibly make a semantic difference whether "and" or "and then" > is used, and similarly "or" vs. "or else". Yes, the AI points that out. >...However, I suspect there > are Ada programmers who habitually use the short-circuit forms (in my >experience, there are very few circumstances where it's *necessary* to >use the logical operator form on boolean operands), and it seems >potentially frustrating to those programmers to force them to go >against their habit when there doesn't seem to be a good reason for >requiring this. I'd probably be convinced by this argument if it weren't so late in the game. [Editor's note: This discussion was restarted on February 2nd.] **************************************************************** From: Brad Moore Sent: Wednesday, December 28, 2011 10:29 AM [Part of a larger review... - Editor] A.18.18 (73.a.1/3) Delete this paragraph, it is almost identical to the preceding paragraph, and the 'Implementation Advice' tag is also redundant, since it falls under the 'Implementation Advice' section. ... If the preceding paragraphs are necessary, then there is a consistency problem, because some of the containers do not have these redundant paragraphs. **************************************************************** From: Randy Brukardt Sent: Friday, December 30, 2011 11:38 PM > A.18.18 (73.a.1/3) Delete this paragraph, it is almost identical to > the preceding paragraph, and the 'Implementation Advice' tag is also > redundant, since it falls under the 'Implementation Advice' section. This is the "marker" note for the what becomes the contents of the Implementation Advice annex (which is automatically generated from these notes). We could consider suppressing these globally (so they aren't shown at all), but doing so would change the paragraph numbers of some AARM notes silently, so that would not be a great idea. ... > If the preceding paragraphs are necessary, then there is a consistency > problem, because some of the containers do not have these redundant > paragraphs. Anything that doesn't have these paragraphs won't show up in the Annex (M.3), which would be a fairly serious bug. There should be one after every implementation advice (or some other note stating that we don't want an annex entry, there is a couple of cases of that). I can't find any missing ones on a quicky random check. If you can, please tell me so that I can fix them somehow. **************************************************************** From: Brad Moore Sent: Saturday, December 31, 2011 10:22 AM The inconsistent containers are ; A.18.22 The Generic Package Containers.Bounded_Ordered_Maps A.18.24 The Generic Package Containers.Bounded_Ordered_Sets **************************************************************** From: Randy Brukardt Sent: Saturday, December 31, 2011 5:25 PM Ah, I see that's intentional, because the wording of the Implementation Advice is identical to the hashed versions. It would look insane to repeat that wording twice in a row in the annex. There should have been a comment in the code (rather than just in the source, where there is one), so you could see why it is omitted. Arguably, omitting these is a bad idea because the section reference is missed in the annex. In that case, we need to change the (normative) wording of all four sets of this advice to add "ordered" and "hashed" appropriately. Should we do that? What do you think? **************************************************************** From: Brad Moore Sent: Tuesday, January 3, 2012 12:22 PM Definitely not a high priority issue, but if it's not too much trouble, I think it would be good to make the changes in the name of consistency, otherwise it looks like an omission. **************************************************************** From: Steve Baird Sent: Monday, January 9, 2012 3:43 PM [Part of a larger review... - Editor] Oh dear. I read 13.11.3 and became very confused. It isn't at all clear for which entities the Default_Storage_Pool aspect may be specified. 5/3 says The language-defined aspect Default_Storage_Pool may be used to define the default pool for access types within an instance. Is this a roundabout way of saying that this aspect may be specified for an instance? It reads like non-normative introductory text. More precise wording is definitely needed, especially when we are doing non-intuitive things like allowing it to be specified via an aspect definition clause for an instance, but only via a pragma for a generic. Or something like that. I can't tell. Did we lose a paragraph or something? **************************************************************** From: Randy Brukardt Sent: Friday, January 13, 2012 1:22 AM ... > Is this a roundabout way of saying that this aspect may be > specified for an instance? Yes (I think). The AARM notes explain the intended model, but I agree that the normative wording ought to match. > It reads like non-normative introductory text. > More precise wording is definitely needed, especially when we > are doing non-intuitive things like allowing it to be > specified via an aspect definition clause for an instance, > but only via a pragma for a generic. Or something like that. > I can't tell. > > Did we lose a paragraph or something? No, that's the wording in the original AI. So it is more that the text was never there. I don't think much additional is actually needed, add a second sentence: "The aspect can be specified for a generic instance". Or maybe it is better to just change the first sentence: The language-defined aspect Default_Storage_Pool may be {specified for a generic instance; it defines} [used to define] the default pool for access types within an instance. **************************************************************** From: Randy Brukardt Sent: Thursday, February 2, 2012 11:18 PM Bob Duff writes: > "Randy Brukardt" wrote: > > Not very-related aside: Do you think that short-circuit forms should > > be allowed in predicate-static expressions? Those of us who almost > > exclusively use "and then" and "or else" will be annoyed every time > > the compiler complains here. > > It was a very deliberate decision to leave them out. But I suppose I > wouldn't object to allowing them. AdaCore style is to use "and then" > in preference to "and". My own personal style is to use "and" unless > "and then" is necessary. The reason I asked is that Ed rejected my suggestion that this be on the Houston agenda, and I'm looking for a second to override that. (Note that I agree that it isn't by any means the most important thing, and if we run out of time it would be a good candidate to skip, but that doesn't mean that we shouldn't have the discussion if we have the time.) RRS has the same style preference to use "and then" as AdaCore. It originally was rooted in efficiency concerns on the Z80 processor (branching took fewer instructions than constructing a boolean value, and we had no optimizer in those days to convert expression to more efficient forms - it wouldn't have fit in the 48K bytes(!!) that we had available then). But I much prefer Robert's justification for AdaCore's style, so I should claim that as the reason. :-) Anyway, since I reflexively write "and then", I am certain to be aggravated every time I write a static predicate. (At least the error would be at the point of declaring the predicate, and not a hundred packages later when I try to use it in a case statement somewhere.) This is the kind of pointless annoyance that Ada is famous for (especially in Ada 83), and I'd rather not introduce another one. I'd give pretty good odds that we'll end up changing it next time to smooth off a bump, so why not consider doing it now and spare everyone the aggravation? So someone out there say "yea, verily", and I'll make an AI to discuss in Houston. If I'm completely alone on this, well, I'll just forget it... **************************************************************** From: Erhard Ploedereder Sent: Friday, February 3, 2012 6:13 AM > So someone out there say "yea, verily", and I'll make an AI to discuss > in Houston. If I'm completely alone on this, well, I'll just forget it... yea, verily. (To push people into if..then..else to say "X /= Null and then X.C = ..." is ... ... ) **************************************************************** From: Robert Dewar Sent: Friday, February 3, 2012 8:57 AM I also say "yea verily verily yea" (those who know Court Jester will have a chant rhythm in their heads when they read this :-)) **************************************************************** From: Jeff Cousins Sent: Friday, February 3, 2012 9:23 AM Just speaking as a random user it would seem bizarre to me not to allow it. **************************************************************** From: Tucker Taft Sent: Friday, February 3, 2012 8:04 AM >> It was a very deliberate decision to leave them out. But I suppose I >> wouldn't object to allowing them. AdaCore style is to use "and then" >> in preference to "and". My own personal style is to use "and" unless >> "and then" is necessary.... I see no reason not to include "and then." I remember asking George Romanski, who is the "main man" when it comes to FAA DO-178Level A certification, and he recommended always using short-circuit in that sort of code. Something about the number of test vectors. Why not include them, other than for personal preference reasons? **************************************************************** From: Bob Duff Sent: Friday, February 3, 2012 9:26 AM > I see no reason not to include "and then." I agree. The AI doesn't explain why I left them out. I think it was just that they're not really needed, combined with the fact that I was afraid the "statically unevaluated" stuff would be a (small) can of worms. But now I think it's not a problem. >...I remember asking > George Romanski, who is the "main man" when it comes to FAA >DO-178Level A certification, and he recommended always using >short-circuit in that sort of code. Something about the number of >test vectors. I'm dubious about arguments based on DO-178B. Airplanes are very safe, but I don't think anybody knows whether DO-178B is responsible for that, nor if so, why. > Why not include them, other than for personal preference reasons? Did you mean to say, "Why not include them, for personal preference reasons?" AFAICS, the only reason to allow them is to accommodate personal preference. **************************************************************** From: Bob Duff Sent: Friday, February 3, 2012 9:17 AM No doubt Randy will want wording. I suggest adding after RM-3.2.4(12/3): a short-circuit control form where both operands are predicate-static; or Note that I'm not messing around with anything analogous to the "statically unevaluated" stuff. ... > (To push people into if..then..else to say > "X /= Null and then X.C = ..." > is ... ... ) That's not predicate static in any case. In fact, as far as I can see, "and" has identical semantics to "and then" in predicate-static expressions. There is no case where "and then" is needed to protect from an exception in the second operand. Can anybody think of a counter-example to prove me wrong? This: subtype S is Integer with Static_Predicate => False and then (Blah / 0) = 0; is illegal (given my above wording), and so is this: subtype S is Integer with Static_Predicate => False and then (1 / S) = 0; I don't see any way to sneak in a divide by zero, nor any other exception. So the only reason to allow "and then" is because people like it. A coding convention "always use and then" is simpler and therefore better than "always use and then, except when it's illegal". **************************************************************** From: Randy Brukardt Sent: Friday, February 3, 2012 11:18 PM > No doubt Randy will want wording. Well, actually, I was going to write it myself (ye how asks and all of that), but thanks for doing it anyway. > I suggest adding after RM-3.2.4(12/3): > > a short-circuit control form where both operands > are predicate-static; or > > Note that I'm not messing around with anything analogous to the > "statically unevaluated" stuff. I would never have even thought to care about that. A predicate that always evaluates to False (or True for that matter) is not very useful, and I don't see any reason to bend over backwards to support it. ... > > yea, verily. > > > > (To push people into if..then..else to say > > "X /= Null and then X.C = ..." > > is ... ... ) > > That's not predicate static in any case. You failed to mention why: dereferencing is not predicate-static, and it couldn't make sense for it to be so. I briefly was confused because X /= null surely is predicate-static. > In fact, as far as > I can see, "and" has identical semantics to "and then" in > predicate-static expressions. There is no case where "and then" is > needed to protect from an exception in the second operand. Right, in large part because we don't allow any math operators in these expressions (they of course can be used in any constituent static expressions). > Can anybody think of a counter-example to prove me wrong? This: > > subtype S is Integer with > Static_Predicate => False and then (Blah / 0) = 0; > > is illegal (given my above wording), and so is this: > > subtype S is Integer with > Static_Predicate => False and then (1 / S) = 0; > > I don't see any way to sneak in a divide by zero, nor any other > exception. Well, invalid values might raise Constraint_Error or Program_Error. But we didn't try to protect against that here, and anyway, those exceptions could rightfully be blamed on the evaluation of the value before the predicate is evaluated. Otherwise, I don't see anyway for a reference to a current instance, a comparison against it, a membership expression using it, or a case expression using it to raise an exception. > So the only reason to allow "and then" is because people like it. > A coding convention "always use and then" is simpler and therefore > better than "always use and then, except when it's illegal". And a lot less aggravating. :-) **************************************************************** From: Randy Brukardt Sent: Saturday, February 4, 2012 12:35 AM 7.3.2(14-15/3) says: Upon successful return from a call on any subprogram or entry that: *is explicitly declared within the immediate scope of type T (or by an instance of a generic unit, and the generic is declared within the immediate scope of type T), and Erhard points out (in a very convoluted way, unfortunately, I wasted 20 minutes writing an explanation before stumbling onto his point), that this means that implicitly declared subprograms, like inherited primitives, aren't covered by invariant checks "on the way back". And this means that 7.3.2(22/3) is a lie, which is surely not our intent. I can't find any reason for the "explicitly" in this bullet, so I've just deleted it, in which case the rules work and the note is true. But I worry that it was there for some good reason. If the reason was to avoid wrappers, well, we decided that we didn't want to do that (as evidenced by the 7.3.2(22/3) note), so then the word is just wrong. If there was any other reason, I can't figure it out, and I didn't find anything in the AIs to help. Anyone else remember? (Tucker in particular.) More generally, anyone know of a reason not to delete this stray "explicitly"? **************************************************************** From: Tucker Taft Sent: Saturday, February 4, 2012 11:10 AM > I can't find any reason for the "explicitly" in this bullet, so I've > just deleted it, in which case the rules work and the note is true. > But I worry that it was there for some good reason. If the reason was > to avoid wrappers, well, we decided that we didn't want to do that (as > evidenced by the > 7.3.2(22/3) note), so then the word is just wrong. I have some trouble parsing your last sentence. Could you clarify? "We didn't want to do that" -- what is "that"? And "the word is just wrong" -- what word? In any case, we spent a lot of time on wording this, and we covered the case of inherited primitives in paragraph 12, because when calling an inherited primitive, there are view conversions applied, and those view conversions do the check (per paragraph 12). Of course some kind of AARM note, or perhaps even a user NOTE, might help clarify this case. > If there was any other reason, I can't figure it out, and I didn't > find anything in the AIs to help. Anyone else remember? (Tucker in > particular.) More generally, anyone know of a reason not to delete > this stray "explicitly"? See above. I believe it is correct as written, given paragraph 12. **************************************************************** From: Randy Brukardt Sent: Saturday, February 4, 2012 4:17 PM > I have some trouble parsing your last sentence. Could you clarify? > "We didn't want to do that" -- what is "that"? And "the word is just > wrong" -- what word? "the word" is "explicitly" in 7.3.2(15/3). "that" is "avoid wrappers". I realize there is a double negative here, but my point is that 7.3.2(22/3) says that we expect to need wrappers for inherited subprograms, so any wording that is intended to avoid such a need is unnecessary. > In any case, we spent a lot of time on wording this, and we covered > the case of inherited primitives in paragraph 12, because when calling > an inherited primitive, there are view conversions applied, and those > view conversions do the check (per paragraph 12). > Of course some kind of AARM note, or perhaps even a user NOTE, might > help clarify this case. There are view conversions to T. What covers the checks on NT on the way out? And if you say the view conversions, then what rule causes the checks on T (in the inherited subprogram) on the way out (because we're not (formally) calling the T routine, so we don't get to apply the rules associated with T). > > If there was any other reason, I can't figure it out, and I didn't > > find anything in the AIs to help. Anyone else remember? (Tucker in > > particular.) More generally, anyone know of a reason not to delete > > this stray "explicitly"? > > See above. I believe it is correct as written, given paragraph 12. Neither Erhard nor I see how paragraph 12 applies. Please explain how this actually works (I realize this has been done before, but please try again). Specifically, in the note 7.3.2(22/3), what rule triggers the check of the invariant of NT for an out parameter (on return from the call))? And why? Similarly for the check of the invariant of T (again on return from the call)? When I read 7.3.2(12/3), it says that a check is made on a view conversion from T to an ancestor of T. It then says something about the same check being made on in out parameters. But that doesn't happen for an "in out" parameter, because the conversion goes from T to NT, and NT is not an ancestor of T. So there is no check to be made in that case. I can easily believe Erhard is wrong, and he got me so confused that I can no longer see what the intent is much less whether the rules cover that intent. (That's why I didn't quote his original message, I didn't want that effect to happen to anyone else.) But it seems to me that something is missing here. I had thought that it just was applying the explicit check to inherited subprograms (that seems to be the easiest way to deal with this), but perhaps 12/3 was supposed to do it (but doesn't). Or maybe 12/3 has mixed up static and dynamic semantics to the point it is incomprehensible... Anyway, thanks in advance for the clear explanation I'm sure to receive. **************************************************************** From: Tucker Taft Sent: Saturday, February 4, 2012 5:00 PM > There are view conversions to T. What covers the checks on NT on the > way out? And if you say the view conversions, then what rule causes > the checks on T (in the inherited subprogram) on the way out (because > we're not > (formally) calling the T routine, so we don't get to apply the rules > associated with T). Here is paragraph 12: After assigning to a view conversion, outside the immediate scope of T, that converts from T or one or more record extensions (and no private extensions) of T to an ancestor of type T, a check is performed on the part of the object that is of type T; similarly, for passing a view conversion as an out or in out parameter outside the immediate scope of T, this check is performed upon successful return; I'm not sure what you meant by "NT" above. Is that the ancestor of T from which it is inheriting the subprogram? I will assume that, even though usually "NT" is meant to signify a *descendant* of T. Anyway, when calling a subprogram inherited by T from its ancestor T0, if there is an invariant that applies to T, then at the point of calling the inherited subprogram, what happens is that the primitive of T0 is called, with all parameters of type T0 in that primitive of T0 being passed view conversions from T to T0. If any of them are OUT or IN OUT parameters, then based on para. 12 above, on the way back, a check is performed on the T part of the object that is identified in the view conversion, which in this case is the whole thing. For example: type T0 is ... procedure Update(X : out T0); ... type T is new T0 with ... with Type_Invariant => Is_Valid(T) = True; -- Update inherited ... Y : T; Update(Y); --> this becomes a call on T0's Update: Update(T0(Y)) --> That "T0(Y)" is a view conversion being --> passed as an OUT parameter, so per para. 12, a --> check on T's invariant is performed --> on Y if the call completes successfully. --> If T0 also has an invariant, then it is checked on T0(Y) --> upon return from the call on T0's Update, and --> if that succeeds, then we would perform T's invariant --> check on Y as a whole. >>> If there was any other reason, I can't figure it out, and I didn't >>> find anything in the AIs to help. Anyone else remember? (Tucker in >>> particular.) More generally, anyone know of a reason not to delete >>> this stray "explicitly"? >> >> See above. I believe it is correct as written, given paragraph 12. > > Neither Erhard nor I see how paragraph 12 applies. Please explain how > this actually works (I realize this has been done before, but please try again). See example above. Let me know if this is not clear. > Specifically, in the note 7.3.2(22/3), what rule triggers the check of > the invariant of NT for an out parameter (on return from the call))? And why? > Similarly for the check of the invariant of T (again on return from > the call)? I don't know how NT relates to T. Hopefully you can make appropriate substitutions into my example above using T and T0. > When I read 7.3.2(12/3), it says that a check is made on a view > conversion from T to an ancestor of T. It then says something about > the same check being made on in out parameters. But that doesn't happen for an "in out" > parameter, because the conversion goes from T to NT, and NT is not an > ancestor of T. So there is no check to be made in that case. I believe you are slightly misreading it. The actual parameter is a "view conversion" from the descendant type to the ancestor type, (from T to T0 in my example) even though upon return, the (conceptual) value conversion actually goes the opposite way, namely from T0 back to T. But of course you can't really do the reverse as a "value conversion" for a tagged type, since you wouldn't know where to come up with the values for the additional components. So there is really no conversion going the other way, it is logically more like an assignment to the T0 part of the actual parameter, so it is more like: T0(Y) := Final_Value_Of_Formal_Param; So again, the view conversion involved is from T to T0. even though the logical flow of data is from an object of type T0 to (the T0 part) of an object of type T. View conversions are confusing. I would recommend rereading 4.6(52-56). For a tagged type, since they are passed by reference, there is no conversion "back" after a call for an OUT parameter. And even if there were, it would have the semantics of the assignment I showed above. > I can easily believe Erhard is wrong, and he got me so confused that I > can no longer see what the intent is much less whether the rules cover > that intent. (That's why I didn't quote his original message, I didn't > want that effect to happen to anyone else.) > > But it seems to me that something is missing here. I had thought that > it just was applying the explicit check to inherited subprograms (that > seems to be the easiest way to deal with this), but perhaps 12/3 was > supposed to do it (but doesn't). Or maybe 12/3 has mixed up static and > dynamic semantics to the point it is incomprehensible... > > Anyway, thanks in advance for the clear explanation I'm sure to receive. I hope I have clarified things, but probably not... **************************************************************** From: Randy Brukardt Sent: Saturday, February 4, 2012 5:54 PM > I hope I have clarified things, but probably not... Doesn't look like it. :-( > I'm not sure what you meant by "NT" above. Is that the ancestor of T > from which it is inheriting the subprogram? I will assume that, even > though usually "NT" is meant to signify a *descendant* of T. Erhard was asking about the "note" 7.3.2(22/3) which talks about types NT and T. I've mentioned that several times, in parts of my messages that you haven't quoted, so I'm not surprised that you missed that. But I think we need to stick to the T and NT types, so we can understand this in terms of the wording that's actually in the RM. > > Specifically, in the note 7.3.2(22/3), what rule triggers the check > > of the invariant of NT for an out parameter (on return from the > > call))? And why? > > Similarly for the check of the invariant of T (again on return from > > the call)? > > I don't know how NT relates to T. Hopefully you can make appropriate > substitutions into my example above using T and T0. That's explained in the note! There's a reason that I specifically mentioned the note above!! Erhard (and by corollary, me) wanted to relate the note to the rules, and neither of us have been able to do it. So now we have three people not paying much attention to each other... (grumble). I would have thought that I didn't have to copy large blocks of text out of the RM because we can read each other... "A call of a primitive subprogram of type NT that is inherited from type T needs to satisfy the specific invariants of both the types NT and T. A call of a primitive subprogram of type NT that is overridden for type NT needs to satisfy only the specific invariants of type NT." Sigh. So I'll try to manually substitute the names of the types in your following text and see if it makes any sense. ... > Anyway, when calling a subprogram inherited by NT from its ancestor T, > if there is an invariant that applies to NT, then at the point of > calling the inherited subprogram, what happens is that the primitive > of T is called, with all parameters of type T in that primitive of T > being passed view conversions from NT to T. Yup, knew that. > If any of them are OUT or IN OUT parameters, then based on para. 12 > above, on the way back, a check is performed on the NT part of the > object that is identified in the view conversion, which in this case > is the whole thing. Maybe that's what's supposed to happen, but I can't see that in 7.3.2(12/3). Maybe the problem is that it talks about "this check" for in out parameters, but the previously described check as nothing to do with this case. The described check goes in the other direction to to the one we need here (because we're going from T to NT here). > For example: > > type T is ... > procedure Update(X : out T); > > ... > > type NT is new T with ... > with Type_Invariant => Is_Valid(NT) = True; > > -- Update inherited > > ... > > Y : NT; > > Update(Y); > --> this becomes a call on T's Update: No, it doesn't. It's a call on NT's update, that executes the body of T with view conversions of the parameters. Ohhh, having looked this up, I see the 3.4(27/2) actually says this. No wonder we have such trouble with overriding, because a model based on real calls has no hope of working in face of multiple inheritance and/or null/abstract subprograms with no implementation. Never mind that though. We have AARM notes in 7.3.2 (22.a/3) that try to explain this, but they way miss the mark because I don't understand the model either. Perhaps you could try clarifying the AARM note to repeat the entire model (it's obvious that hardly anyone, even inside the ARG, understands it, so writing notes that assume that they do isn't helping much). The AARM note at least has to mention the call model and have a cross-reference to 3.4. Here's an attempt: Proof: This follows from the definition of inheritance as view conversions of the parameters of the type {and a call to the original routine (see 3.4)}, along with {the normal invariant checking rules}[ the rules require checks on such view conversions]. {In particular, the call to the original routine takes care of any checks needed on type T, and the checks required on view conversions take care of any checks needed on type NT, specifically on in out and out parameters.} We require this in order that the semantics of an explicitly defined wrapper that does nothing but call the original routine is the same as that of an inherited routine. Can this be clearer still?? > Update(T(Y)) > > --> That "T(Y)" is a view conversion being > --> passed as an OUT parameter, so per para. 12, a > --> check on NT's invariant is performed > --> on Y if the call completes successfully. > --> If T also has an invariant, then it is checked on T(Y) > --> upon return from the call on T's Update, and > --> if that succeeds, then we would perform NT's invariant > --> check on Y as a whole. Back to paragraph 12/3 and the note 22/3. The note says that the above is what happens, so it's pretty obvious that this is the intent. But I can't see how to get this out of paragraph 12/3, beyond your say-so. ... > > When I read 7.3.2(12/3), it says that a check is made on a view > > conversion from T to an ancestor of T. It then says something about > > the same check being made on in out parameters. But that doesn't > > happen for an "in out" > > parameter, because the conversion goes from T to NT, and NT is not > > an ancestor of T. So there is no check to be made in that case. > > I believe you are slightly misreading it. The actual parameter is a > "view conversion" from the descendant type to the ancestor type, (from > NT to T in my example) even though upon return, the (conceptual) value > conversion actually goes the opposite way, namely from T back to NT. > But of course you can't really do the reverse as a "value conversion" > for a tagged type, since you wouldn't know where to come up with the > values for the additional components. So there is really no > conversion going the other way, it is logically more like an > assignment to the T part of the actual parameter, so it is more like: > > T(Y) := Final_Value_Of_Formal_Param; > > So again, the view conversion involved is from NT to T. > even though the logical flow of data is from an object of type T to > (the NT part) of an object of type NT. > > View conversions are confusing. I would recommend rereading > 4.6(52-56). For a tagged type, since they are passed by reference, > there is no conversion "back" after a call for an OUT parameter. And > even if there were, it would have the semantics of the assignment I > showed above. Well, duh, it's obvious that they're confusing. Even with your roadmap here I'm skeptical. I can't imagine how an ordinary user would ever be able to figure out when this would happen (and that's necessary for understanding the cause of failures). At least part of the problem here is all of the emphasis on what the view conversion goes to (which is backwards from anything that we care about). I have to wonder if we care about any of that in the first place. Are there any view conversions from a *private* type (and outside the package) that we would *not* care about? I mean, don't we need to do this even for derived scalar types? (If T and NT are ultimately scalar types or access types, don't we still want the same checks of their invariants?) And you can't convert to a more derived type (that would require adding components, which isn't possible). So what am I missing So, I guess what I'm saying, is what is wrong with something like: After assigning to a view conversion, outside the immediate scope of T, that converts an object of type T to some other type, a check is performed on the part of the object that is of type T; similarly, for passing a view conversion as an out or in out parameter outside the immediate scope of T, this check is performed upon successful return; And even here I'd prefer to get rid of the "from" and "to" (since they're confusing beyond belief), unfortunately, I wasn't able to do it. Perhaps we could just drop the "to some other type" (irrelevant as previously noted), but that seems a bit vague: After assigning to a view conversion, outside the immediate scope of T, that converts an object of type T, a check is performed on the object; similarly, for passing a view conversion as an out or in out parameter outside the immediate scope of T, this check is performed upon successful return; (I dropped the whole "the part of the object" here, because it is irrelevant for the reverse type conversion -- the check is on the result of that reverse type conversion, which is the entire object. You'd need to check only a part if you were making the forward check to the ancestor, but if I understand you correctly, that is not the part that this rule is covering. To wit: an assignment to a view conversion of NT to T assigns just the T part, but the check is on the entire NT object.) By now, I have this completely wrong. Enjoy straightening me out... :-) **************************************************************** From: Erhard Ploedereder Sent: Saturday, February 4, 2012 7:08 PM Tuck, my original (convoluted?) comment was: >> ================ >>> 7.3.2 22/3 I cannot identify the rule that requires the check of the >>> specific invariant of type NT for the return from an inherited >>> subprogram of T. (It's neither 12/3 nor 14-18/3. >>> So, where is the rule? >>> Alternatively, this part of the note would need to become a rule.) I did not think that 12/3 covered the case. The first sentence talks exclusively about upcasts. The second says "similarly", so upcasts only. The note says: 13 A call of a primitive subprogram of type NT that is inherited from type T needs to satisfy the specific invariants of both the types NT and T. A call of a primitive subprogram of type NT that is overridden for type NT needs to satisfy only the specific invariants of type NT. (Come to think of it, now the second sentence of the Note becomes very mysterious, too, since for a redefinition dispatchingly called via the parent method such an upcast would happen on the way out and hence invariants of T would be checked.) **************************************************************** From: Tucker Taft Sent: Sunday, February 5, 2012 12:03 PM > I did not think that 12/3 covered the case. The first sentence talks > exclusively about upcasts. The second says "similarly", so upcasts > only. Oh boy, now we are changing the vocabulary again! By "upcast" I presume you mean a view conversion from a descendant to an ancestor. The important thing to realize is that a view conversion is *writable*. It doesn't really convert the data, it just provides a narrowed view of it, so you only see the ancestor part of some descendant. Through a view conversion you can willy-nilly change the ancestor part of the descendant object, using assignments, passing as OUT parameters, etc. The challenge is that the type-invariant on a descendant might depend on the consistency between data residing in the ancestor part with data in the extension part(s) after that. So if someone changes the ancestor part, then we need to recheck the various invariants of any descendants. > The note says: > 13 A call of a primitive subprogram of type NT that is inherited from > type T needs to satisfy the specific invariants of both the types NT > and T. A call of a primitive subprogram of type NT that is overridden > for type NT needs to satisfy only the specific invariants of type NT. OK, sorry I missed the reference to the Note. Thanks for copying it here. So what this is saying is that if NT inherits an operation from T rather than overriding it, both the T invariant is checked, and then the NT invariant. Paragraph 12 ensures that the NT invariant is checked, because a call on an inherited subprogram turns into a call on the ancestor's subprogram with controlling parameters being view conversions, so [IN] OUT controlling parameters which are view conversions will trigger para 12. The normal semantics of the subprogram call on the original T subprogram takes care of the check on the T invariant. If you override with a new NT subprogram, then T's invariant isn't checked as part of the call on this new subprogram. On the other hand, if inside this subprogram there is a call on a primitive of T to update the T "part" of the object, then there will be a check on T's invariant at that point. But that is buried inside the NT primitive, and we aren't worried about that in this note. > (Come to think of it, now the second sentence of the Note becomes very > mysterious, too, since for a redefinition dispatchingly called via the > parent method such an upcast would happen on the way out and hence > invariants of T would be checked.) You are using "upcast" in a way that is totally non-Ada-like here. There is *no* separate T-to-NT view conversion "on the way out," on any sort of call. In fact, normally there is absolutely nothing that happens "on the way out." All the "damage" has already been done, since tagged types, including view conversions thereof, are passed by *reference.* But with Type_Invariants we now *do* have something done "on the way out." But the view conversion is still syntactically and semantically going from NT to T, even though you might logically think of this as some kind of "upcast" back to NT. *Don't think about it that way!* You will get yourself totally confused (and take Randy along with you ;-). **************************************************************** From: Erhard Ploedereder Sent: Sunday, February 5, 2012 3:32 PM > Oh boy, now we are changing the vocabulary again! > By "upcast" I presume you mean a view conversion from a descendant to > an ancestor. Merely too lazy to spell out "a view conversion, outside the immediate scope of T, that converts from T or one or more record extensions (and no private extensions) of T to an ancestor of type T". I'll stay lazy and call this mouthful an "upcast" in this msg. > You are using "upcast" in a way that is totally non-Ada-like here. > There is *no* separate T-to-NT view conversion "on the way out," > on any sort of call. My 2 a.m. mistake. I remembered the rule 6.4.1 (17): "After normal completion and leaving of a subprogram, for each in out or out parameter that is passed by copy, the value of the formal parameter is converted to the subtype of the variable given as the actual parameter and assigned to it." which for inherited ops is an "upcast" NT->T, but I forgot that by-reference types are excepted from being safe at this point and do not require "upcast" semantics. > But the view conversion is still syntactically and semantically going > from NT to T, even though you might logically think of this as some > kind of "upcast" back to NT. *Don't think about it that way!* You > will get yourself totally confused (and take Randy along with you . O.k., I'll try not to. But I am still trying to understand the model and find the rules for it. Here is my example and exegesis.... Type T is tagged private; procedure P(X:T); Type NT is new T; ... O: T'Class := new NT; P(O); (1) I get different semantics wrt the specific type invariants, depending on whether NT redefines P. This is a bit unusual, but o.k., since these are specific invariants. The semantics are.... (2) When NT redefines P, then I get the specific type invariant checks for NT from the implicit view conversion T->NT on the way in (11/3), and then again from the return of the call (15/3-17/3 all apply), unless it is an "in" parameter (which happens to be the case here). For "in" and "in out" parameters, (12/3) would require the very same check again for a redefinition. (3) When NT inherits P, then I get the specific type invariant checks for NT from the implicit view conversion T->NT on the way in (11/3), and then the check for T because ...... that is the rule that I had problems finding, since 17/3 and hence all of 14/3-18/3 does not apply -- my O is an "in" parameter. So where is the rule that makes the check for T in my example? (Don't I wish there were! But that is the "other discussion".) If there isn't one, the note is incorrect (unless, and this is a momentary afterthought, "needs to satisfy the invariant" is not equivalent to saying "needs to pass the invariant check", but the "other discussion" appears to go that way.). About: > The normal semantics of the subprogram call on the original T > subprogram takes care of the check on the T invariant. which in their entirety are spelled out by 14/3-18/3, right? So, no help there. **************************************************************** From: Tucker Taft Sent: Sunday, February 5, 2012 3:59 PM > (2) When NT redefines P, then I get the specific type invariant checks > for NT from the implicit view conversion T->NT on the way in (11/3), > and then again from the return of the call (15/3-17/3 all apply), > unless it is an "in" parameter (which happens to be the case here). > For "in" and "in out" parameters, (12/3) would require the very same > check again for a redefinition. Now you have confused me. If NT redefines P, then there are no view conversions involved. So the only check that is relevant is any invariant on NT itself. T is irrelevant at this point. And as you point out below, P has no outputs, so no invariant checks. > (3) When NT inherits P, then I get the specific type invariant checks > for NT from the implicit view conversion T->NT on the way in (11/3), > and then the check for T because ...... that is the rule that I had > problems finding, since 17/3 and hence all of 14/3-18/3 does not apply > -- my O is an "in" parameter. No invariant checks at all on an IN parameter (unless you get us to change that). Make the mode "OUT" and then we have something to discuss. > So where is the rule that makes the check for T in my example? > (Don't I wish there were! But that is the "other discussion".) There are no checks on IN parameters, and the note in 22 certainly should be interpreted as implying there are. > If there isn't one, the note is incorrect (unless, and this is a > momentary afterthought, "needs to satisfy the invariant" is not > equivalent to saying "needs to pass the invariant check", but the > "other discussion" appears to go that way.) So you are complaining it doesn't repeat all of the earlier discussion? It is simply warning the user that above (in 12-21) we talk about the checks associated with a call, and the NOTE is saying that if the operation is inherited, then you need to worry about both the ancestor and the descendant type. **************************************************************** From: Randy Brukardt Sent: Sunday, February 5, 2012 4:09 PM ... > O.k., I'll try not to. But I am still trying to understand the model > and find the rules for it. Here is my example and exegesis.... > > Type T is tagged private; > procedure P(X:T); > > Type NT is new T; > ... > > O: T'Class := new NT; > P(O); > > (1) I get different semantics wrt the specific type invariants, > depending on whether NT redefines P. This is a bit unusual, but o.k., > since these are specific invariants. > The semantics are.... > > (2) When NT redefines P, then I get the specific type invariant checks > for NT from the implicit view conversion > T->NT on the way in (11/3), and then again from the return of > the call (15/3-17/3 all apply), unless it is an "in" > parameter (which happens to be the case here). > For "in" and "in out" parameters, (12/3) would require the very same > check again for a redefinition. When NT redefines P, there are no view conversions anywhere in the calls to the redefined P, and thus no checks. Unless you are talking about those occurring in an explicit body, and then the checks are on conversions to type T, not NT. That is, the redefinition of P is: procedure P (X : NT) is begin P (T (X)); end P; There are no checks on NT anywhere here. If X is an in out parameter, there is a check on T on the way in, and checks on both T and NT on the way out. The check on T on the way in seems to be a mistake (I don't think there should be any checks on the way in), but doesn't seem possible to eliminate it. > (3) When NT inherits P, then I get the specific type invariant checks > for NT from the implicit view conversion > T->NT on the way in (11/3), and then the check for T because > ...... that is the rule that I had problems finding, since > 17/3 and hence all of 14/3-18/3 does not apply -- my O is an "in" > parameter. This is an in parameter, so there should be no checks at all. The check from an explicit conversion is unnecessary in this case, but as I said, that seems like a bug. Invariant checks are only on the way out of subprograms. There are never any on the way in. The only way to get checks on the way in is to explicit write something that forces a check (like an explicit conversion). > So where is the rule that makes the check for T in my example? > (Don't I wish there were! But that is the "other discussion".) There is no check intended, so there is no rule! > If there isn't one, the note is incorrect (unless, and this is a > momentary afterthought, "needs to satisfy the invariant" > is not equivalent to saying "needs to pass the invariant check", but > the "other discussion" appears to go that way.). The note is fine, it is only talking about in out and out parameters (there being no checks of any kind on in parameters). **************************************************************** From: Erhard Ploederder Sent: Sunday, February 5, 2012 4:35 PM > Conversions that "cross" T are also checked. > That is perhaps what makes para 12 confusing, but it is there for a > reason. right. I worked it through and, apart from the "in" issue, the whole thing works. In fact, I had played through the following example, and then deleted it from the mail, since it did not add to my case... Type PT is tagged private; procedure P(X: in out PT); type T is new PT; -- inherits P(X: in out T); Type NT is new T; ... O: T'Class := new NT; P(O); Now, if NT inherits P, you get checks for PT and NT. If it redefines, checks are for NT only. **************************************************************** From: Erhard Ploederder Sent: Sunday, February 5, 2012 4:38 PM > For "in" and "in out" parameters, (12/3) would require the very same > check again for a redefinition. Of course, I meant > For "out" and "in out" parameters, (12/3) would require the very same > check again for a redefinition. **************************************************************** From: Erhard Ploederder Sent: Sunday, February 5, 2012 5:01 PM > When NT redefines P, there are no view conversions anywhere in the > calls to the redefined P Live and learn. I had it in my mind that a dispatching call achieved the "change" from T'Class via T (the spec to which the name binds) to NT (the impl dispatched to) by means of a trivially successful view conversion (as it would have to, if one mapped the dispatching scheme to an underlying monomorphic type system). I was wrong. **************************************************************** From: Erhard Ploederder Sent: Sunday, February 5, 2012 5:09 PM A version of the note that I would have no problems with would be 13 For a call of a primitive subprogram of type NT that is inherited from type T, the specified checks of the specific invariants of both the types NT and T are performed. For a call of a primitive subprogram of type NT that is overridden for type NT, the specified checks of the specific invariants of only type NT are performed. ------ the present version for comparison: > 13 A call of a primitive subprogram of type NT that is inherited from > type T needs to satisfy the specific invariants of both the types NT > and T. A call of a primitive subprogram of type NT that is overridden > for type NT needs to satisfy only the specific invariants of type NT. **************************************************************** From: Tucker Taft Sent: Sunday, February 5, 2012 6:56 PM Works for me. **************************************************************** From: Randy Brukardt Sent: Sunday, February 5, 2012 3:14 PM ... > OK, sorry I missed the reference to the Note. Yes, I know that. Despite the fact that I mentioned it three times. Grrrr. ... > Paragraph 12 ensures that the NT invariant is checked, because a call > on an inherited subprogram turns into a call on the ancestor's > subprogram with controlling parameters being view conversions, so [IN] > OUT controlling parameters which are view conversions will trigger > para 12. > The normal semantics of the subprogram call on the original T > subprogram takes care of the check on the T invariant. That's what paragraph 12 should say, but it is bogged down in verbal diarrhea; it babbles on about things that are irrelevant and thus confuses the issue to the point where I'm not even convinced it's right. So I want to start over with that text. I proposed a rewording in a previous message that you didn't read, and since I figure you won't read this one either (at least not in detail), I'll explain that in a separate message. **************************************************************** From: Tucker Taft Sent: Sunday, February 5, 2012 3:28 PM > ... So, I guess what I'm saying, is what is wrong with something like: > > After assigning to a view conversion, outside the immediate scope of > T, that converts an object of type T to some other type, a check is > performed on the part of the object that is of type T; similarly, for > passing a view conversion as an out or in out parameter outside the > immediate scope of T, this check is performed upon successful return; The problem is that if a view conversion goes from a (proper) descendant of T to a (proper) ancestor of T, then there are checks as well. So it is not just when you convert from T itself. Conversions that "cross" T are also checked. That is perhaps what makes para 12 confusing, but it is there for a reason. > > And even here I'd prefer to get rid of the "from" and "to" (since > they're confusing beyond belief), unfortunately, I wasn't able to do > it. Perhaps we could just drop the "to some other type" (irrelevant as > previously noted), but that seems a bit vague: > > After assigning to a view conversion, outside the immediate scope of > T, that converts an object of type T, a check is performed on the > object; similarly, for passing a view conversion as an out or in out > parameter outside the immediate scope of T, this check is performed > upon successful return; Again, I believe you are losing the checks that arise in view conversions that "cross" T, but don't start at T. > (I dropped the whole "the part of the object" here, because it is > irrelevant for the reverse type conversion -- the check is on the > result of that reverse type conversion, which is the entire object. > You'd need to check only a part if you were making the forward check > to the ancestor, but if I understand you correctly, that is not the part that this rule is covering. > To wit: an assignment to a view conversion of NT to T assigns just the > T part, but the check is on the entire NT object.) > > By now, I have this completely wrong. Enjoy straightening me out... > :-) See above. I do remember struggling with this wording in Edinburgh, and almost every word in para. 12 was debated. So fixing it won't be easy without losing something. **************************************************************** From: Randy Brukardt Sent: Sunday, February 5, 2012 3:55 PM [Editor's note: This message crossed in the mail with Tucker's previous message.] As noted in my last message, now that I understand (again) the intent, it's clear to me that 7.3.2(12/3) is far more complex a rule than needed. It should be simplified. [For those of you with limited time, feel free to skip to the end of this message to see the payoff. But if you have questions, *read* my message, don't ask questions that I've already answered!] Starting from principles. What we're trying to accomplish with these checks is essentially: Outside of the package of type T, any modification of an object of type T should be checked that the invariant of T holds after the modification. OK, let's get more specific about the case of interest: Outside of the package of type T, any object of type T where all or some part of the object is replaced by an object of some other type should be checked that the invariant of T holds after the replacement. Since T has to be a private type, there aren't many cases of this. The case of interest involves view conversions. Still speaking informally, that means we're interested in the following case: Outside of the package of type T, any assignment (implicit or explicit) to a view conversion with a source of type T should be checked that the invariant of T holds after the assignment. It's important to note here that the target type of the conversion is completely irrelevant. It does not matter what type the replaced part of the object is, because we need to check the whole object afterwards. We also don't need to talk about "parts", because a view conversion can only change the type of the object itself, not that of any components. (There is no view conversion of an array of NT becoming an array of T, for instance.) Even if the only kind of view conversion (I'm not certain) that is relevant is a tagged extension conversion, that's irrelevant to both the reason for the check and the details of the check. So leave it out! Similarly, since this check can never have anything to do with parts, leave that out too. All of that extra wording just confuses the important issues. I think we also want to be a bit more explicit about what is being checked (also to avoid confusion). Now, I realize the wording I have above is too informal; the "in out" parameter case is not really an assignment at all. So we have to have a separate sentence to cover that. And we need something to handle the visible extension case (but again, this should apply to any derived type, not just extensions). The key is to think only of conversions between directly related types. So here's my attempt: Outside the immediate scope of T: * after assigning to a view conversion that converts an object of T, a check is performed on the object; * after a call that passes a view conversion of an object of T as an out or in out parameter, a check is performed on the actual object. For the purposes of determining the need for these checks, each view conversion is considered a set of nested view conversions including each visible ancestor between the source and target types. Discussion: The last rule means that if we have: type T is ... type NT is new T ... type NNT is new NT ... Obj : NNT; P (... T(Obj) ...); then the checks are applied as if the view conversion was NT(T(Obj)). I'm sure this can be improved. The other thing that needs to be improved is the AARM note that tries to explain 22/3, perhaps if it had been more explicit we would have headed off Erhard's original complaint. I put a suggestion into a previous message, and I'm not going to confuse the issue including it here. **************************************************************** From: Randy Brukardt Sent: Monday, February 6, 2012 10:04 PM > > ... So, I guess what I'm saying, is what is wrong with something like: > > > > After assigning to a view conversion, outside the immediate scope of > > T, that converts an object of type T to some other type, a check is > > performed on the part of the object that is of type T; similarly, > > for passing a view conversion as an out or in out parameter outside > > the immediate scope of T, this check is performed upon successful > > return; > > The problem is that if a view conversion goes from a (proper) > descendant of T to a (proper) ancestor of T, then there are checks as > well. So it is not just when you convert from T itself. Conversions > that "cross" T are also checked. > That is perhaps what makes para 12 confusing, but it is there for a > reason. See the message that I was writing at the same time as this one. I covered that case. Note that an important part of the confusion is mentioning the type that we're converting to: the wording says that it is an "ancestor", and that seems to combine with the other parts of the wording. But it's definitely the case that the type we convert to is irrelevant, and shouldn't be mentioned at all, or at least should simply say "some other type". Part of the problem with the "from" wording is that it seems to imply a need for "to", which we don't care about here. Beyond that, I still stick to my contention that "extensions" are irrelevant for the reasons for the rule, and we ought to try to mention them as little as possible. Indeed, I much prefer mentioning them at the end in a "similarly" clause, rather than confusing everything by sticking them into the main text. --------- Now for the important part: I think that the semantics described in the existing rule is wrong, or (more accurately) different for the inherited and explicitly written routines. It's not crystal clear that this should be fixed (all of these cases are corner cases to start with), but I wanted to raise the issue. If we are inheriting a routine from a grandparent, as in: type T is tagged private with Invariant => InvT; procedure P (A : in out T); Obj_T : T; ... type NT is new T ... with Invariant => InvNT; -- Inherits procedure P (A : in out NT); from T Obj_NT : NT; ... type NNT is new NT ... with Invariant => InvNNT; -- Inherits procedure P (A : in out NNT); from NT Pbj_NNT : NNT; We agree that a call P(Obj_NT) is translated to P(T(Obj_NT)), and this evaluates both InvT and InvNT when the routine returns (InvT from the normal rules for the body, InvNT from the view conversion rule). I believe that a call P(Obj_NNT) is translated to P(NT(Obj_NNT), which then (after applying the previous rule) becomes P(T(NT(Obj_NNT))). That means that such a "doubly inherited call" this evaluates all of InvT, InvNT, InvNNT when the routine returns (because we have two view conversions here). This is good because this is the natural implementation; the wrapper for NT's P would become the called body for the inherited P for NNT. OTOH, it's likely that if someone wrote this explicitly, they'd write: P(T(Obj_NNT)). Given the way 7.3.2(12/3) is written, this is *not* the same thing; only InvT and InvNNT would be evaluated for this call. I think it would be better if the semantics included any intervening invariant (that is, effectively you would make the checks for each intervening derived types). Then T(Obj_NNT) would be exactly equivalent to T(NT(Obj_NNT)). And as I noted in my message yesterday, if this is the case, then there is no need to special case any extensions (you'll pick up any invariants in the walk from the target type to the source type). What I don't know is what the intended semantics of a "doubly inherited call" is. I can't find a compelling reason to insist on evaluating InvNT (in the example above), so perhaps the intent was that the "middle" invariant not be evaluated. If so, the semantics are wrong for that case, and we need to revisit the wording for that reason. (I'd prefer to require it be evaluated, all other things being equal, but of course they're rarely equal.) I'll take another crack at improving this wording, but I'd like to know what the intended semantics are. > See above. I do remember struggling with this wording in Edinburgh, > and almost every word in para. 12 was debated. So fixing it won't be > easy without > losing something. I think that we lost sight of the big picture in favor of patching up the bug-de-jour. The general principle is very simple (outside of the package defining T, check anything that might modify an object of type T), and the case in question is pretty simple (after changing the result of a view conversion with source T, make a check of the invariant of T). The only question is whether intervening types need to be checked, or whether talking about types related to T is enough. **************************************************************** From: Jean-Pierre Rosen Sent: Tuesday, February 7, 2012 7:01 AM > I think it would be better if the semantics included any intervening > invariant (that is, effectively you would make the checks for each > intervening derived types). Then T(Obj_NNT) would be exactly > equivalent to T(NT(Obj_NNT)). And as I noted in my message yesterday, > if this is the case, then there is no need to special case any > extensions (you'll pick up any invariants in the walk from the target type to the source type). > > What I don't know is what the intended semantics of a "doubly > inherited call" is. I can't find a compelling reason to insist on > evaluating InvNT (in the example above), so perhaps the intent was > that the "middle" invariant not be evaluated. I fully agree with you (that InvNT should be evaluated). Remember that in OO reasoning, an NNT "is a" NT (which "is a" T). Therefore, any invariant for NT should hold for NNT. Imagine that the additional components added by NT depend on the components of T. If the invariants for NT are not evaluated, you could create an object whose NT part does not obey its invariant. **************************************************************** From: Tucker Taft Sent: Tuesday, February 7, 2012 8:46 AM One issue that I just thought of has to do with view conversions from a class-wide type to an ancestor's specific type. If you assign to such a view conversion, it is not clear at compile-time how many type invariants you will need to check. I fear this means creating a type-invariant-checking implicit dispatching operation. Yuck. For example: type T is ... private ... with Type_Invariant => Valid(T); type NT is new T with private with Type_Invariant => NT_Valid(NT); type NNT is new NT with private with Type_Invariant => NNT_Valid(NNT); X : T'Class := ... T(X) := ... -- How many type-invariant checks need to be performed? Nasty... **************************************************************** From: Bob Duff Sent: Tuesday, February 7, 2012 9:24 AM > ...I fear this > means creating a type-invariant-checking implicit dispatching > operation. Yuck. Doesn't seem SO horrible. I mean, relative to some other implemetation horrors I can think of. **************************************************************** From: Tucker Taft Sent: Tuesday, February 7, 2012 9:57 AM True, but it was totally unexpected as far as I was concerned. I guess what the compiler will need to do is create an implicit dispatching operation which will take two parameters, an object and a level, and check the type invariant on the object, and if the level implies it, call the corresponding type-invariant-checking routine of its parent type. The level would indicate the "extension level" of the target type of the view conversion. Or I suppose it might want to call its parent type's type-invariant checker first if the level number indicates it is appropriate, and then if that passed (or was bypassed), check its own. Not that hard to do but annoying to have to create yet another implicit dispatching operation for the oddball case involving class-wide objects. **************************************************************** From: Randy Brukardt Sent: Friday, February 10, 2012 2:07 AM > I guess what the compiler will need to do is create an implicit > dispatching operation which will take two parameters, an object and a > level, and check the type invariant on the object, and if the level > implies it, call the corresponding type-invariant-checking routine of > its parent type. The level would indicate the "extension level" > of the target type of the view conversion. This seems more complicated than necessary. Here's how I described this for the AARM: For view conversions involving class-wide types, the exact checks needed may not be known at compile-time. One way to deal with this is to have an implicit dispatching operation that is given the object to check and the tag of the target of the conversion, and which first checks if the passed tag is not for itself, and if not, checks the its invariant on the object and then calls the operation of its parent type. If the tag is for itself, the operation is complete. This tag comparison is the same as (the much more common) one needed for checking type conversions to descendant class-wide types for inclusion. And each such routine only makes a single check for each type, it doesn't try to pile all of them up, or invent a "extension level". If we have to have a dispatching routine, we might as well leverage that. (BTW, I don't find this that unusual. I think we have more than 10 such routines already, what's one more??) **************************************************************** From: Tucker Taft Sent: Tuesday, February 7, 2012 1:09 PM ... > I think it would be better if the semantics included any intervening > invariant (that is, effectively you would make the checks for each > intervening derived types). Then T(Obj_NNT) would be exactly > equivalent to T(NT(Obj_NNT)). And as I noted in my message yesterday, > if this is the case, then there is no need to special case any > extensions (you'll pick up any invariants in the walk from the target type to the source type). This could also be fixed by eliminating the mention of record extensions vs. private extensions in para 12 (which you have been recommending), and require the invariant checks on all types that are "crossed" by a view conversion be checked: After assigning to a view conversion, outside the immediate scope of T, that converts from [T or one or more record extensions (and no private extensions) of T] {a descendant of T (including T itself)} to an ancestor of type T {(other than T itself)}, a check is performed on the part of the object that is of type T; similarly, for passing a view conversion as an out or in out parameter outside the immediate scope of T, this check is performed upon successful return; > What I don't know is what the intended semantics of a "doubly > inherited call" is. I can't find a compelling reason to insist on > evaluating InvNT (in the example above), so perhaps the intent was > that the "middle" invariant not be evaluated. If so, the semantics are > wrong for that case, and we need to revisit the wording for that > reason. (I'd prefer to require it be evaluated, all other things being > equal, but of course they're rarely equal.)... It seems that the intermediate invariant should be re-checked, since if you change the ancestor part, then you could easily invalidate invariants of every descendant. **************************************************************** From: Randy Brukardt Sent: Wednesday, February 8, 2012 10:25 PM > This could also be fixed by eliminating the mention of record > extensions vs. private extensions in para 12 (which you have been > recommending), and require the invariant checks on all types that are > "crossed" by a view conversion be checked: > > After assigning to a view conversion, outside the immediate scope of > T, that converts from [T or one or more record extensions (and no > private extensions) of T] {a descendant of T (including T itself)} to > an ancestor of type T {(other than T itself)}, a check is performed > on the part of the object that is of type T; similarly, for passing a > view conversion as an out or in out parameter outside the immediate > scope of T, this check is performed upon successful return; Ah, this is what I trying to get to on Sunday. As usual, your wording is better than mine. I'll write up the change this way (replacing last week's work). I still wonder if the second branch (the in out case) is a bit too vague; it never says that it is only talking about view conversions that meet the conversion rules of the previous branch. That's kind of important, and it's easy to read it that way because the part about being outside of the scope is repeated, but not the type part. Perhaps it would be better to repeat the entire thing and use bullets for the non-repeated part: For a view conversion, outside the immediate scope of T, that converts from a descendant of T (including T itself) to an ancestor of type T {(other than T itself), a check is performed on the part of the object that is of type T: * after assigning to the view conversion; and * after successful return from a call that passes the view conversion as out or in out parameter. Now there is no confusion about which cases are included (no vague similarly), and there's almost no duplication of wording. I think this is a big improvement, and is great. :-) What about the rest of you?? P.S. I think either of these wordings would benefit from an AARM note that explains that a single view conversion could trigger this rule for multiple types and thus cause multiple invariant checks. **************************************************************** From: Tullio Vardanega Sent: Thursday, February 9, 2012 2:24 AM The latest formulation is becoming digestible even to the likes of me. Perhaps this counts as an indication of convergence ;-) **************************************************************** From: Randy Brukardt Sent: Friday, February 17, 2012 12:36 AM The following is literally the last comment that I have to address: >4.9 (11/3) a membership test whose simple_expression is a static > expression, and whose membership_choice_list consists only of > membership_choices each of which is either a static >choice_expression, > a static range, or a subtype_mark that denotes a static > [(scalar or string)] subtype; > > this sentence might need to be improved for readability, > >Suggested rewording... > >" a membership test whose simple_expression is a static expression and > whose membership_choice_list consists only of membership_choices that > are one of the following: > - a static choice_expression; or > - a static range; or > - a subtype_mark that denotes a static (scalar or string) subtype;" > >or alternatively, > >" a membership test whose simple_expression is a static expression and > whose membership_choice_list consists only of membership_choices that > must be one of; a static choice_expression, a static range, or a > subtype_mark that denotes a static (scalar or string) subtype;" We can't use "must" in normative wording, and its replacement "shall" should only apply to Legality Rules and the like, so the second choice is out. Using the bullets within a bulleted list can be confusing (it's out of context here, of course), so I'm unconvinced that it is an improvement. I suppose we could use a variation on the second choice: " a membership test whose simple_expression is a static expression and whose membership_choice_list consists only of membership_choices that are be one of: a static choice_expression, a static range, or a subtype_mark that denotes a static (scalar or string) subtype;" But I find the embedded colon weird, so I don't have a clear answer. I still prefer the original wording. Any thoughts? (Must arrive here by 2pm tomorrow.) **************************************************************** From: Tucker Taft Sent: Friday, February 17, 2012 8:37 AM > But I find the embedded colon weird, so I don't have a clear answer. I > still prefer the original wording. I prefer the bulleted sub-list or the original wording. With the bulleted sub-list, I would stick with the singular, namely: a membership test whose simple_expression is a static expression and whose membership_choice_list consists of membership_choices each of which is one of the following: - a static choice_expression; or - a static range; or - a subtype_mark that denotes a static (scalar or string) subtype; **************************************************************** From: Gary Dismukes Sent: Friday, February 17, 2012 12:03 PM > Any thoughts? (Must arrive here by 2pm tomorrow.) I would stick with the original wording, which I find acceptable. ... except, not being able to leave well enough alone, I'd add a comma before "each of which": 4.9 (11/3) a membership test whose simple_expression is a static expression, and whose membership_choice_list consists only of membership_choices{,} each of which is either a static choice_expression, a static range, or a subtype_mark that denotes a static [(scalar or string)] subtype; **************************************************************** From: Tucker Taft Sent: Friday, February 17, 2012 12:14 PM > 4.9 (11/3) a membership test whose simple_expression is a static > expression, and whose membership_choice_list consists only of > membership_choices{,} each of which is either a static choice_expression, > a static range, or a subtype_mark that denotes a static > [(scalar or string)] subtype; I don't see the need to say "consists only of." Why not simply "consists of"? The only things allowed in a membership_choice_list are membership_choices. The "only" is redundant with "each of which" if that was its purpose. **************************************************************** From: Gary Dismukes Sent: Friday, February 17, 2012 3:14 PM I agree, now that you point it out, that "only" doesn't make sense. After all, membership_choices are the only things there can be. If we take that out, then a comma shouldn't be added. **************************************************************** From: Randy Brukardt Sent: Friday, February 17, 2012 7:50 PM Odd. I thought it still was needed: 4.9 (11/3) a membership test whose simple_expression is a static expression, and whose membership_choice_list consists of membership_choices, each of which is either a static choice_expression, a static range, or a subtype_mark that denotes a static [(scalar or string)] subtype; "...consists of membership_choices each of which is..." doesn't seem right to me. But with the comma in, the middle part of kinda silly (a choice list made of up of choices, who'da thunk it??) Maybe the problem isn't the "only", but the "each of which". Try getting rid of it and make the items plural: 4.9 (11/3) a membership test whose simple_expression is a static expression, and whose membership_choice_list consists only of membership_choices that are either static choice_expressions, static ranges, or subtype_marks that denote a static [(scalar or string)] subtype; Of course, we had something like this early on, and it got changed to the current one. I know Tucker prefers singular terms, but I don't think we should worry about that if it is damaging comprehension. Last call for better ideas... **************************************************************** From: Tucker Taft Sent: Saturday, February 18, 2012 10:45 AM I still prefer singular wherever possible, but using "that" instead of "each of which" in this case does get some benefit, and means that the "only" is not redundant. So I can live with your suggestion. ****************************************************************