!standard 3.2.4(4/4) 14-09-29 AI12-0099-1/03 !standard 3.2.4(12/3) !standard 3.2.4(20/3) !class binding interpretation 14-05-12 !status Corrigendum 1-2012 14-07-23 !status WG9 Approved 14-10-20 !status ARG Approved 7-0-0 14-06-28 !status work item 14-05-12 !status received 14-02-21 !priority Low !difficulty Easy !qualifier Omission !subject Wording problems with predicates !summary (1) 3.2.4(12/3) applies to a type declared by any type of declaration, not just a derived type declaration. In particular, it applies to task types and protected types. (2) "not" is an allowed operator in a predicate-static expression. !question (1) Consider the case of a task type with progenitors: task type Tsk is new Intf with ... end Tsk; Since Tsk does not have a predicate specification, 3.2.4(8/3-11/3) do not apply. 3.2.4(12/3) doesn't apply either, as Tsk is not a derived type declaration. 3.2.4(13/3) does not apply as Tsk is not a subtype_indication. So I can only conclude that 3.2.4(14/3) applies. That of course means that any predicates of Intf will never be checked as part of Tsk, other than in memberships, no matter what the assertion policy is (anywhere). It's pretty clear that 3.2.4(12/3) is intended to apply to this case. As with 3.2.4(4/3) [now 4/4], the original author seems to have missed that a task type or protected type is not a derived type declaration, but that they can have progenitors and need to be treated similarly to a derived type declaration. Do we need to change "derived type declaration" to "type declaration" in 3.2.4(12/3)? (Yes.) (2) There does not seem to be a definition of the term "logical operator" (no underscore) as used in RM 3.2.4(20/3). In particular, it does not appear to include the "not" operator. (An English term that is not otherwise defined is usually taken to mean the same as the associated syntax term, and "logical_operator" does not include "not". The index entry for logical operator has "See also not operator" but that seems hardly a normative definition! Thus it appears that "not" cannot be used in a "predicate-static" expression. Should we fix the wording to make it clear that "not" is allowed in predicate-static expressions? (Yes.) !recommendation (See Summary.) !wording Modify 3.2.4(4/4) [as modified by AI12-0071-1]: * For a (first) subtype defined by a {type declaration}[type_declaration], {any}[the] predicates of [the] parent {or}[subtype and the] progenitor subtypes apply. Modify 3.2.4(12/3): * If a subtype is defined by a [derived] type declaration that does not include a predicate specification, then predicate checks are enabled for the subtype if and only if {any} predicate checks are enabled for [at least one of the] parent {or}[subtype and the] progenitor subtypes; Modify 3.2.4(20/3): * a call to a predefined boolean [logical] operator {and, or, xor, or not}, where each operand is predicate-static; !discussion (1) AI12-0071-1 made a similar change to 3.2.4(4/4), to correct essentially the same problem in a different rule. We clearly missed the fact that there are two such rules. Note that "type declaration" is not the syntax term "type_declaration" in either this rule or 3.2.4(4/4), as we need to include the anonymous task type associated with a single_task_declaration (which is not a "type_declaration"), and similarly for single_protected_declaration. We change 3.2.4(4/4) this way because the editor failed to understand the meaning of the Steve Baird comment in AI12-0071-1 and thus got it wrong. (2) As noted in the question, the typical policy for the Standard is to have otherwise undefined terms to have the same meaning as the syntax term that results from swapping spaces for underscores. In this case, that means that "not" is not a logical operation. It certainly is illogical for "not" to be excluded from logical operators, but that's been true since at least Ada 80, so changing that after more than 33 years is more likely to introduce bugs into the Standard than to fix any. So we opt to just fix the predicate-static wording to avoid any confusion. !corrigendum 3.2.4(4/4) @drepl @xbullet, the predicates of the parent subtype and the progenitor subtypes apply.> @dby @xbullet !corrigendum 3.2.4(12/3) @drepl @xbullet @dby @xbullet !corrigendum 3.2.4(20/3) @drepl @xbullet @dby @xbullet, @b, @b, or @b, where each operand is predicate-static;> !ASIS No ASIS effect. !ACATS test For (1), it would be possible to create a C-Test to ensure this is done correctly. It would be a fairly low priority test as we don't expect predicates to be common on progenitors (of any kind). For (2), it should be part of proper tests for predicate-static expressions; a separate test shouldn't be needed. !appendix From: Randy Brukardt Sent: Friday, February 21, 2014 7:59 PM I'm working on potential test objectives for predicates, and I noticed a problem with the rules for when predicates are enabled [3.2.4(7/3-14/3)]. [Note: This has little to do with the discussion last fall, as this case doesn't depend on assertion policy -- indeed that's the bug.] Consider the case of a task type with progenitors: task type Tsk is new Intf with -- Not the "with" of an aspect -- specification; too many "with"s -- potentially here! ... end Tsk; Since Tsk does not have a predicate specification, 3.2.4(8/3-11/3) do not apply. 3.2.4(12/3) doesn't apply either, as Tsk is not a derived type declaration. 3.2.4(13/3) does not apply as Tsk is not a subtype_indication. So I can only conclude that 3.2.4(14/3) applies. That of course means that any predicates of Intf will never be checked as part of Tsk, other than in memberships, no matter what the assertion policy is (anywhere). It's pretty clear that 3.2.4(12/3) is intended to apply to this case. As with 3.2.4(4/3) [now 4/4], the original author seems to have missed that a task type or protected type is not a derived type declaration, but that they can have progenitors and need to be treated similarly to a derived type declaration. Probably we need to change "derived type declaration" to "type declaration" in 3.2.4(12/3), just as we did that in 3.2.4(4/4) by AI12-0071-1 (to correct a similar problem in a different definition). **************************************************************** From: Tucker Taft Sent: Wednesday, February 26, 2014 9:08 AM There does not seem to be a definition of the term "logical operator" (no underscore) as used in RM 3.2.4(20/3). In particular, it is not clear that it includes the "not" operator. The index entry for logical operator has "See also not operator" but that seems hardly a normative definition! This is relevant because it determines whether "not" may be used in a "predicate-static" expression. **************************************************************** From: Jeff Cousins Sent: Wednesday, February 26, 2014 9:22 AM Isn't "logical operator" a well enough known term without the RM having to define it? The RM isn't using the term differently from what people would have been taught at school. **************************************************************** From: Tucker Taft Sent: Wednesday, February 26, 2014 9:31 AM True, but the one place the term appears in a definitional setting, it talks only about and/or/xor. Furthermore, the syntactic construct "logical_operator" only includes and/or/xor. So it seems a bit confusing to assume "not" should be included in the term "logical operator" without any mention of that fact other than in the index. It would be easy to add a parenthetical remark where "not" is discussed that it is a logical operator. **************************************************************** From: Bob Duff Sent: Wednesday, February 26, 2014 10:20 AM > talks only about and/or/xor. Furthermore, the syntactic construct > "logical_operator" only includes and/or/xor. So it seems a bit > confusing to assume "not" should be included in the term "logical > operator" without any mention of that fact other than in the index. If you search for "logical operator", it seems pretty clear that NOT is NOT included, surprisingly. It seems intended to mean logical_operator, in Ada 83. See 4.5.1. See also RM-A.1: 8 -- The predefined logical operators and the predefined logical -- negation operator are as follows: 9/1 {8652/0028} {AI95-00145-01} -- function "and" (Left, Right : Boolean'Base) return Boolean'Base; -- function "or" (Left, Right : Boolean'Base) return Boolean'Base; -- function "xor" (Left, Right : Boolean'Base) return Boolean'Base; 10/1 {8652/0028} {AI95-00145-01} -- function "not" (Right : Boolean'Base) return Boolean'Base; On the other hand RM-3.5.4 (Ada 95): NOTES ... same operators are predefined, plus bit-wise logical operators (and, or, xor, and not). I wouldn't bother fixing any of that, but instead list the 4 operators in 3.2.4(20/3). **************************************************************** From: Robert Dewar Sent: Wednesday, February 26, 2014 12:57 PM > Isn't "logical operator" a well enough known term without the RM having to > define it? The RM isn't using the term differently from what people would > have been taught at school. Well it confused me, especially since it seemed artificial to be talking about "each" of the operands of NOT. And it resulted in my first pass of implementing this section of the RM being wrong in that excluded NOT. **************************************************************** From: Robert Dewar Sent: Wednesday, February 26, 2014 12:59 PM > True, but the one place the term appears in a definitional setting, it > talks only about and/or/xor. Furthermore, the syntactic construct > "logical_operator" only includes and/or/xor. So it seems a bit confusing to > assume "not" should be included in the term "logical operator" without any > mention of that fact other than in the index. It would be easy to add a > parenthetical remark where "not" is discussed that it is a logical operator. I would prefer to just make the reference explicit in including NOT, it would not have avoided my confusion to have a buried statement a mile away in the RM. **************************************************************** From: Randy Brukardt Sent: Wednesday, February 26, 2014 5:13 PM > If you search for "logical operator", it seems pretty clear that NOT > is NOT included, surprisingly. It seems intended to mean > logical_operator, in Ada 83. See 4.5.1. The standard seems to have an informal rule that in the absence of a definition to the contrary, normal text is equivalent to the matching syntax term (with spaces replaced by underscores). I once tried to eliminate such usages but it's a never ending task that has the potential to introduce bugs so I gave up. For instance, "assignment statement" is the same as "assignment_statement". There are some cases to the contrary, which makes things messier -- in particular, the infamous cases of "body" (which includes the syntactical body as well as null procedures, expression functions, and entry bodies) and "function call" (which includes the syntactical function_call as well as infix operator calls). In an ideal world, we would always use the syntax term if we meant that, and English would be reserved for cases where we meant something else, but that's not the world of the RM. --- To answer the original question, 3.2.4(20/3) should probably say something like (with appropriate boldfacing of the keywords): * a call to a predefined boolean operator and, or, xor, or not, where each operand is predicate-static; or even: * a call to a predefined boolean logical_operator, where each operand is predicate-static; * a call to a predefined boolean not operator, where the operand is predicate-static; The latter for those who can't stand "each" being used for a single operand operator. **************************************************************** From: Robert Dewar Sent: Wednesday, February 26, 2014 6:48 PM > To answer the original question, 3.2.4(20/3) should probably say > something like (with appropriate boldfacing of the keywords): > > * a call to a predefined boolean operator and, or, xor, or not, where > each operand is predicate-static; that would have been fine > or even: > > * a call to a predefined boolean logical_operator, where each operand > is predicate-static; > * a call to a predefined boolean not operator, where the operand is > predicate-static; > > The latter for those who can't stand "each" being used for a single > operand operator. I didn't say I couldn't stand it, I just said that in the absence of a clear definition of logical operator, and hints like the following: > 2 The following logical operators are predefined for every boolean type T, > for every modular type T, and for every one-dimensional array type T > whose component type is a boolean type: > > 3 function "and"(Left, Right : T) return T > function "or" (Left, Right : T) return T > function "xor"(Left, Right : T) return T The use of each just helped imply that not was not included. As long as the list is explicit there is no problem. ****************************************************************