!standard 11.3(4/2) 13-01-30 AI12-0054-1/04 !standard 13.9.2(2) !standard 13.9.2(3/3) !class binding interpretation 12-12-08 !status Amendment 202x 13-01-30 !status work item 13-02-25 Letter ballot failed (10-2-2) !status work item 12-12-08 !status received 12-12-07 !priority High !difficulty Medium !qualifier Error !subject A raise_expression does not cause membership failure !summary Consider: subtype S is Integer with Dynamic_Predicate => Is_Gnarly(S) or else raise Program_Error; then a membership test "X in S" does not raise Program_Error just because Is_Gnarly(X) returns False. Similarly, "X'Valid" does not raise Program_Error just because Is_Gnarly(X) returns False. !question AI12-0022-1, "Raise expressions for specifying the exception raised for an assertion" added the ability to control which exception is raised by failure of various assertions. This is an important capability, because it allows to change interfaces to use assertions while preserving compatibility. However, this feature doesn't work properly for predicates, because predicates are evaluated by membership tests, so we would get spurious failures. Should these spurious failures be removed from the language, so that raise_expressions can be used in predicates? (Yes.) !recommendation See !summary. !wording 11.3(4/2) was amended by AI12-0022-1 as follows: ... For the execution of a raise_statement with an exception_name, the named exception is raised. {Similarly, for the evaluation of a raise_expression, the named exception is raised.} [{In both of these cases, if}[If] a string_expression is present, the expression is evaluated and its value is associated with the exception occurrence.] ... Add a new paragraph after that: There is one exception to the above rule: For an individual membership test (see 4.5.2) of the form "X in S", if a raise_expression @Redundant[statically] within the predicate of S is evaluated, then the exception is not raised; instead, the entire predicate immediately evaluates to False. This includes raise_expressions @Redundant[statically] within the default_expression for a formal parameter used in a call @Redundant[statically] within the predicate. AARM Discussion: But it does NOT include raise_expressions within the default_expression for a component; those actually raise the exception. Modify 13.9.2(2-3/3) so it refers to the semantics of "in" rather than directly to the semantics of the predicate, so the newly-modified semantics of "in" automatically work for 'Valid: 2 For a prefix X that denotes a scalar object Redundant[(after any implicit dereference)]{of nominal subtype S}, the following attribute is defined: 3/3 X'Valid Yields True if and only if the object denoted by X is normal, has a valid representation, and the [predicate of the nominal subtype of X]{the membership test "X in S"} evaluates to True. The value of this attribute is of the predefined type Boolean. !discussion Note that "within" in the new wording means statically/textual containment as usual. We're not talking about anything dynamic. But we do include formal parameter defaults. The purpose of a raise_expression in an assertion is to specify which exception is raised on failure. For example: subtype S is Integer with Dynamic_Predicate => Is_Round(S) or else raise Program_Error; is not really saying that Program_Error should be raised. It is saying that Is_Round should be True for all objects of subtype S (and, oh by the way, if it's not, then Program_Error should be raised instead of the usual exception). That works just fine for parameter passing and the like: procedure P(X: S); ... P(X); If Is_Round(X) is False on the call, Program_Error is raised as expected. But if we have: Some_Integer : Integer := ...; ... if Some_Integer in S then ... we don't want to raise Program_Error. We want the 'if' condition to return True or False according to whether Is_Round(X) is True. Therefore, we change the rule so that "Is_Round(S) or else raise Program_Error" is evaluated as "Is_Round(S) or else predicate-is-False" -- but only for membership tests. Note that this special case for raise_expressions in membership tests does not apply to any other ways of raising an exception. For example, if Is_Round(X) propagates an exception, then the membership test propagates that exception occurrence. This unfortunately means you cannot in general make use of abstraction by moving an (entire) existing predicate into a function body (or expression function); to make that transformation you need to leave the "raise" part behind. The following example shows how to raise a particular exception for a particular "reason" the predicate fails. If the evaluation of "X in T" evaluates one of the raise_exceptions, then "X in T" will be False. type T is ... with Predicate => (T >= First_Allowed or else raise Too_Small) and then (T <= Last_Allowed or else raise Too_Big) and then (Is_Good(T) or else raise Badness); Rationale for the default_expression business: A defaulted parameter really should be strongly equivalent to an explicit parameter. Switching from one to the other should not cause subtle changes in run-time semantics. The component case is less clear. We choose to treat those in the opposite way (the exception is raised) because otherwise there would be an implementation difficulty for implementations that choose to wrap default initializations in an initialization procedure (whether or not inlined), because an extra "we're in an 'in'" flag would need to be passed. Intended implementation: If the implementation chooses to generate code for predicates inline at the places where they are used, then it would be appropriate to replace "raise ..." with a jump to "return False from the predicate" whenever the predicate is being evaluated as part of a membership test. If an implementation uses an out-of-line function to evaluate the predicate, it can pass an extra "In_Membership" flag, or it can generate two copies of the function. Either way, the raise isn't replaced by False -- it is replaced by a jump to a place that returns False for the whole predicate. The above type T with mixed "and then" and "or else" shows why. An implementation that wraps the predicate with an exception handler like "when others => False" would be incorrect. An implementation that turns "raise ..." into "False" would also be wrong. !corrigendum 11.3(4/2) @drepl To @i is to raise a new occurrence of that exception, as explained in 11.4. For the execution of a @fa with an @i@fa, the named exception is raised. If a @i@fa is present, the @fa is evaluated and its value is associated with the exception occurrence. For the execution of a re-raise statement, the exception occurrence that caused transfer of control to the innermost enclosing handler is raised again. @dby To @i is to raise a new occurrence of that exception, as explained in 11.4. For the execution of a @fa with an @i@fa, the named exception is raised. Similarly, for the evaluation of a @fa, the named exception is raised. In both of these cases, if a @i@fa is present, the @fa is evaluated and its value is associated with the exception occurrence. For the execution of a re-raise statement, the exception occurrence that caused transfer of control to the innermost enclosing handler is raised again. There is one exception to the above rule: For an individual membership test (see 4.5.2) of the form "X @b S", if a @fa statically within the predicate of S is evaluated, then the exception is not raised; instead, the entire predicate immediately evaluates to False. This includes @fas statically within the @fa for a formal parameter used in a call statically within the predicate. !corrigendum 13.9.2(2) @drepl For a @fa X that denotes a scalar object (after any implicit dereference), the following attribute is defined: @dby For a @fa X that denotes a scalar object (after any implicit dereference) of nominal subtype @i, the following attribute is defined: !corrigendum 13.9.2(3/3) @drepl @xhang<@xtermYields True if and only if the object denoted by X is normal, has a valid representation, and the predicate of the nominal subtype of X evaluates to True. The value of this attribute is of the predefined type Boolean.> @dby @xhang<@xtermYields True if and only if the object denoted by X is normal, has a valid representation, and the membership test "X @b @i" evaluates to True. The value of this attribute is of the predefined type Boolean.> !ACATS Test One or more ACATS C-Tests will be needed to test this semantics (and to ensure that neither of the "wrong" implementations are used). !ASIS No effect (AI12-0022-1 will take care of any issues). !appendix This AI was created out of a problem noted during discussion on AI12-0037-1 during ARG meeting #48 in Boston. **************************************************************** From: Tucker Taft Sent: Saturday, December 8, 2012 12:06 PM I think a raise expression in a predicate should yield False only if it has a boolean expected type. **************************************************************** From: Randy Brukardt Sent: Thursday, January 24, 2013 4:39 PM ... > OK, I've included a new version below. Thanks. One comment: ... > !wording > > 11.3(4/2) was amended by AI12-0022-1 as follows: > > ... For the execution of a raise_statement with an exception_name, the > named exception is raised. {Similarly, for the evaluation of a > raise_expression, the named exception is raised.} [{In both of these > cases, if}[If] a string_expression is present, the expression is > evaluated and its value is associated with the exception occurrence.] > ... > > Add a new paragraph after that: > > There is one exception to the above rule: For an individual membership > test (see 4.5.2) of the form "X in S", if a raise_expression within > the predicate of S is evaluated, then the exception is not raised; > instead, the entire predicate immediately evaluates to False. This > includes raise_expressions within the default_expression for a formal > parameter. Later you informally explain that "within" means textually within (with the inclusion of default parameters of calls). However, every time I read this normative wording, I read it as "anywhere within", and I know that's not what we mean. (After all, this is dynamic semantics, so usually textual considerations don't apply.) I think we need some sort of qualifier on "within" to make it clearer that this is textual, not dynamic. Perhaps something like: There is one exception to the above rule: For an individual membership test (see 4.5.2) of the form "X in S", if a raise_expression immediately within the predicate of S is evaluated, then the exception is not raised; instead, the entire predicate immediately evaluates to False. For the purpose of this exception, raise_expressions within the default_expression for a formal parameter used in a call immediately within the predicate are considered immediately within the predicate. [There's too many words in this last sentence, but you get the idea.] Or we could use "textually" rather than "immediately" here. The rest of the AI looks good. **************************************************************** From: Tucker Taft Sent: Thursday, January 24, 2013 4:57 PM > ... Later you informally explain that "within" means textually within > (with the inclusion of default parameters of calls). However, every > time I read this normative wording, I read it as "anywhere within", > and I know that's not what we mean. (After all, this is dynamic > semantics, so usually textual considerations don't apply.) I think we > need some sort of qualifier on "within" to make it clearer that this is > textual, not dynamic. I would vote for "textually within" or "statically within" (favoring the latter). **************************************************************** From: Bob Duff Sent: Thursday, January 24, 2013 5:07 PM > Later you informally explain that "within" means textually within > (with the inclusion of default parameters of calls). However, every > time I read this normative wording, I read it as "anywhere within", > and I know that's not what we mean. (After all, this is dynamic > semantics, so usually textual considerations don't apply.) I think we > need some sort of qualifier on "within" to make it clearer that this is > textual, not dynamic. Well, I think we often (always?) use "within" in the textual sense in the RM. > Perhaps something like: > > There is one exception to the above rule: For an individual membership > test (see 4.5.2) of the form "X in S", if a raise_expression > immediately within the predicate of S is evaluated, then the exception > is not raised; instead, the entire predicate immediately evaluates to > False. For the purpose of this exception, raise_expressions within the > default_expression for a formal parameter used in a call immediately > within the predicate are considered immediately within the predicate. I think "immediately within" could be confusing, because that's a formal term defined in Chap 8, and it refers to declarative regions. (It's definitely textual.) > [There's too many words in this last sentence, but you get the idea.] Yes, too many words, I think. > Or we could use "textually" rather than "immediately" here. I like that better. I suggest using my paragraph as is, except with the two occurrences of "within" replaced by "Redundant[textually] within". I suggest you commit my changes as is, and then commit another version with "textually" added twice, so people can see the diff's. > The rest of the AI looks good. OK, thanks, maybe we can vote on this soon. **************************************************************** From: Bob Duff Sent: Thursday, January 24, 2013 5:08 PM > I would vote for "textually within" or "statically within" > (favoring the latter). Either one is OK with me, but I think it should be @Redundant. **************************************************************** From: Randy Brukardt Sent: Thursday, January 24, 2013 5:34 PM > > Later you informally explain that "within" means textually within > > (with the inclusion of default parameters of calls). However, every > > time I read this normative wording, I read it as "anywhere within", > > and I know that's not what we mean. (After all, this is dynamic > > semantics, so usually textual considerations don't apply.) I think we > > need some sort of qualifier on "within" to make it clearer > > that this is textual, not dynamic. > > Well, I think we often (always?) use "within" in the textual sense in > the RM. I view it as ambiguous; I'm likely to use "within" as a short-hand for "during the evaluation of" when discussing dynamic semantics. Whether that's made it into the normative wording, I don't know. > > Perhaps something like: > > > > There is one exception to the above rule: For an individual > > membership test (see 4.5.2) of the form "X in S", if a > > raise_expression immediately within the predicate of S is evaluated, > > then the exception is not raised; instead, the entire predicate > > immediately evaluates to False. For the purpose of this exception, > > raise_expressions within the default_expression for a formal > > parameter used in a call immediately within the predicate are considered > > immediately within the predicate. > > I think "immediately within" could be confusing, because that's a > formal term defined in Chap 8, and it refers to declarative regions. > (It's definitely textual.) Yes, that could be true. > > [There's too many words in this last sentence, but you get > the idea.] > > Yes, too many words, I think. > > > Or we could use "textually" rather than "immediately" here. > > I like that better. I suggest using my paragraph as is, except with > the two occurrences of "within" replaced by "Redundant[textually] > within". I don't like the last sentence of your original wording much, because I wondered where the heck a "formal parameter" occurs in a predicate expression (there are only actual parameters in such an expression - someone might think you are talking about the current instance as if it is a parameter, but that's not the intent). Moreover, the statement is ambiguous, because you only mean to include default expressions that are used in calls that are "statically within" or "textually within" or whatever term you use the predicate expression -- it surely doesn't apply to some random default expression that occurs inside of some called function. Finally, if you are formally talking about something that occurs "textually within", by no stretch of the imagination can that apply to a default expression. Thus I wanted to make these points clear (I know I overdid it, I was hoping for a bit of wordsmithing, not outright rejection). The only reason this made any sense to me at all is because I know what rule you are trying to encapsulate -- I'm not sure how Adam (for example) was going to figure that out. The idea I had was to "simply" say that a default_expression is considered statically within the predicate expression, but it didn't work out so simple when I made it crystal clear. I'm sure the appropriate wording is somewhere between our two proposals. > I suggest you commit my changes as is, and then commit another version > with "textually" added twice, so people can see the diff's. OK, although I would prefer a clearer version of the last sentence. > > The rest of the AI looks good. > > OK, thanks, maybe we can vote on this soon. Hope so too. **************************************************************** From: Jeff Cousins Sent: Monday, January 28, 2013 8:08 AM I think Randy's point about clarifying what is meant by "formal parameter" is more important than what (if any) word precedes "within". **************************************************************** From: Bob Duff Sent: Monday, January 28, 2013 10:32 AM > I think Randy's point about clarifying what is meant by "formal > parameter" is more important than what (if any) word precedes "within". Well, I still think my suggestion is best. I can't imagine how "statically within" could be confused to mean dynamically. If folks don't like it, then please propose an alternative. Randy comments: > I don't like the last sentence of your original wording much, because > I wondered where the heck a "formal parameter" occurs in a predicate > expression ... But it doesn't say that. It's clearly (to me ;-)) talking about a default expression FOR a formal parameter. It's the default expression that is "within...". (Of course it's only implicitly there -- that's what defaults do.) I'm ready to vote on the AI, with "statically within". If others are not, we need alternative wording. **************************************************************** From: Jeff Cousins Sent: Monday, January 28, 2013 10:44 AM Extend "This includes raise_expressions within the default_expression for a formal parameter." to "This includes raise_expressions within the default_expression for a formal parameter used in a call within the predicate." **************************************************************** From: Robert Dewar Sent: Monday, January 28, 2013 10:47 AM > Extend "This includes raise_expressions within the default_expression > for a formal parameter." to "This includes raise_expressions within > the default_expression for a formal parameter used in a call within > the predicate." I am fine with any of the wording suggestions here, the intent is obvious (I just finished implementing this feature :-)) **************************************************************** From: Bob Duff Sent: Monday, January 28, 2013 11:18 AM > Extend "This includes raise_expressions within the default_expression > for a formal parameter." to "This includes raise_expressions within > the default_expression for a formal parameter used in a call within > the predicate." Looks good to me. **************************************************************** From: Randy Brukardt Sent: Monday, January 28, 2013 7:29 PM "{statically} within the predicate". Thanks Jeff for making this suggestion as it avoids the need for me to invoke "Editor's discretion" to fix this sentence, as I found the original unacceptable. (That's a power I'd rather avoid using very often.) **************************************************************** From: Tucker Taft Sent: Friday, February 1, 2013 9:41 AM [The relevant part of a larger message - Editor.] ... Two editorial comments: ... In AI12-0054, the new wording starts "There is one exception to the above rule: ..." I don't remember ever seeing wording like this in the RM. Is there some other way we could accomplish this, or do we agree that this is the best way to introduce this special case? It is also a bit odd (or Bob intentionally being ironic?) to be talking about one "exception" to the evaluation rules for "raise blah"... ;-) **************************************************************** From: Bob Duff Sent: Friday, February 1, 2013 9:55 AM > In AI12-0054, the new wording starts "There is one exception to the above rule: ..." > I don't remember ever seeing wording like this in the RM. It seems clear enough to me. It seems better than some other paragraphs, where we try to weave a tangled web of exceptions all into one sentence, "Blah blah blah, except on odd Tuesdays, other than those following the autumnal equinox, during leap years, ..." Anyway, I think the burden is on you (or someone besides me) to suggest an alternative. >...Is there some > other way we could accomplish this, or do we agree that this is the >best way to introduce this special case? It is also a bit odd (or Bob >intentionally being ironic?) to be talking about one "exception" > to the evaluation rules for "raise blah"... ;-) The "irony" just an accidental side effect of the wording I chose. ;-) **************************************************************** From: Tucker Taft Sent: Friday, February 1, 2013 10:11 AM ... > Anyway, I think the burden is on you (or someone besides me) to > suggest an alternative. I'll try to craft something. My first instinct is to put the dynamic semantics of the raise-expression into its own paragraph, rather than trying to shoe-horn it into the paragraph describing the raise statement. Once it is in its own paragraph, the special case of use in predicates can be given more prominence. This can also address the issue of not evaluating the string expression when appearing in a membership test. **************************************************************** From: Robert Dewar Sent: Friday, February 1, 2013 10:17 AM I think the wording is fine as is, I would not spend too much time word smithing here unless you feel there is something that is unclear. **************************************************************** From: Steve Baird Sent: Friday, February 1, 2013 12:48 PM > I'll try to craft something. Thanks Tuck. I agree that it is worth going to some effort to avoid You know that stuff we said earlier? It wasn't quite right. wording. It's not *so* bad if the modifier comes immediately after the wording it is overriding (as in this case), but it can still lead to confusion (e.g., if someone searching the RM for the answer to some question reads the modified rule without going on to read the modification), IMO, it would suffice to add a hint that a modification is coming. Perhaps something like Except as described below, ... If a rule which is going to be overridden/modified later acknowledges this explicitly, that should be enough of a cue to avoid confusion. **************************************************************** From: Steve Baird Sent: Friday, February 1, 2013 1:28 PM Editorial comment: In the !discussion section for AI12-0054, we've got If the evaluation of "X in T" evaluates one of the raise_exceptions, then "X in T" will be True. Is this a Boolean-off-by-one error? **************************************************************** From: Randy Brukardt Sent: Friday, February 1, 2013 6:12 PM > > In AI12-0054, the new wording starts "There is one > exception to the above rule: ..." > > I don't remember ever seeing wording like this in the RM. ... > Anyway, I think the burden is on you (or someone besides me) to > suggest an alternative. Yes. Not to mention that we've been discussing the wording of this paragraph for the last week, it could have been brought up earlier. (And this bothered me since I first saw the wording at the meeting; there never was an appropriate point to bring it up when I wasn't writing notes and no one else seemed concerned so I didn't push to inject that.) **************************************************************** From: Tucker Taft Sent: Sunday, February 3, 2013 10:17 AM Here is a possible update to the wording proposed for AI12-0054. It puts the rules for raise_expressions in a separate paragraph. It includes updates to the wording of 11.4.1 as well. It attempts to clarify that the string_expression is evaluated before creating the new exception occurrence. ----------------------- Modify 11.3(4/2) as follows: To raise an exception is to raise a new occurrence of that exception@Redundant[, as explained in 11.4]. For the execution of a raise_statement with an exception_name, {the string_expression, if any, is evaluated, and then} the named exception is raised. @Redundant[If a string_expression is present, [the expression is evaluated and] its value is associated with the exception occurrence.] For the execution of a re-raise statement, the exception occurrence that caused transfer of control to the innermost enclosing handler is raised @Redundant[again]. Add the following after 11.3(4/2): For a raise_expression, if it occurs @Redundant[statically] within the predicate for a subtype (after expanding any default_expressions used for calls occurring within the predicate), and the subtype is named in a membership_choice, evaluating the raise_expression causes the associated individual membership test to evaluate immediately to True. In other contexts, evaluating a raise_expression begins with the evaluation of the string_expression, if any, and then the named exception is raised, as for a raise_statement. Modify 11.4.1(10.1/3) as follows: Exception_Message returns the message associated with the given Exception_Occurrence. For an occurrence raised by a call to Raise_Exception, the message is the Message parameter passed to Raise_Exception. For the occurrence raised by a raise_statement {or raise_expression} with an exception_name and a string_expression, the message is the {value of the} string_expression. For the occurrence raised by a raise_statement {or raise_expression} with an exception_name but without a string_expression, the message is a string giving implementation-defined information about the exception occurrence. For an occurrence originally raised in some other manner (including by the failure of a language-defined check), the message is an unspecified string. In all cases, Exception_Message returns a string with lower bound 1. **************************************************************** From: Bob Duff Sent: Sunday, February 3, 2013 11:42 AM > Here is a possible update to the wording proposed for AI12-0054. I don't really think this is an improvement. Your wording for 11.3(4/2) puts an obscure exceptional case first, which is confusing. My wording puts the exceptional case later, where (IMHO) it should be. Also, you're changing and adding a lot more verbiage, which doesn't seem like a good idea. Some of the wording changes look gratuitous to me (i.e. not fixing any real bugs). >...It puts the > rules for raise_expressions in a separate paragraph. It includes >updates to the wording of 11.4.1 as well. It attempts to clarify that >the string_expression is evaluated before creating the new exception I also think this discussion is a waste of time. I'd rather accept > your wording than continue to argue about it for another week. > If everybody but me agrees with Tuck, then I'll happily give in. I prefer Bob's wording, but really don't care it is amazingly unimportant. I also agree with all the points Bob made. **************************************************************** From: Randy Brukardt Sent: Monday, February 4, 2013 2:16 PM > > Here is a possible update to the wording proposed for AI12-0054. > > I don't really think this is an improvement. Your wording for > 11.3(4/2) puts an obscure exceptional case first, which is confusing. > My wording puts the exceptional case later, where (IMHO) it should be. This I agree with. Steve's suggestion (adding "except as indicated below" or something like that to the normal case) is better than Tucker's version. > Also, you're changing and adding a lot more verbiage, which doesn't > seem like a good idea. Some of the wording changes look gratuitous to > me (i.e. not fixing any real bugs). I'm not as convinced about that. > >...It puts the > > rules for raise_expressions in a separate paragraph. It includes > >updates to the wording of 11.4.1 as well. It attempts to > clarify that > >the string_expression is evaluated before creating the new > exception occurrence. > > Well, I claim that that doesn't need clarification. This I agree with as well. We wrote this as a Ramification AI specifically because the language is clear enough for everyone other than language lawyers. > I also think this discussion is a waste of time. I'd rather accept > your wording than continue to argue about it for another week. > If everybody but me agrees with Tuck, then I'll happily give in. Well, I don't like either version; I prefer Steve's enhancement, plus removing the redundant marks around the existing text about evaluation of the string expression. Something like (here, changes are marked from the AI12-0022-1 version): To raise an exception is to raise a new occurrence of that exception Redundant[, as explained in 11.4]. For the execution of a raise_statement with an exception_name, the named exception is raised. Similarly, {except as noted below,} for the evaluation of a raise_expression, the named exception is raised. In both of these cases, if a string_expression is present, the expression is evaluated and its value is associated with the exception occurrence. For the execution of a re-raise statement, the exception occurrence that caused transfer of control to the innermost enclosing handler is raised Redundant[again]. This eliminates the only problem with the existing wording vis-a-vis the evaluation order (that it is marked as redundant, but there is no other text that talks about evaluation of the string_expressions), and eliminates Steve's concern that the special case isn't mentioned in the original wording. I could see adding "value of the" to 11.4.1(10.1/3) [because it's the evaluated value, not the expression itself that's associated with the exception occurrence], but it's hardly critical (especially if the existing text is not thought of as redundant). Removing the "pun" from the new paragraph would nice, but hardly worth a bunch of discussion. **************************************************************** Editor's note: (February 25, 2013) This AI failed its letter ballot 10-2-2 (Dewar and Rosen opposing, Barnes and Burns abstaining, Baird, Bosch, Brukardt, Cousins, Dismukes, Duff, Moore, Ploedereder, Schonberg, Taft in favor). Our rules require no opposing votes to for e-mail ballots to pass (rules are looser at meetings). Subsequent e-mail discussion led to creating an alternative, AI12-0054-2; the e-mail is filed in that AI. ****************************************************************