Version 1.5 of ai12s/ai12-0054-1.txt

Unformatted version of ai12s/ai12-0054-1.txt version 1.5
Other versions for file ai12s/ai12-0054-1.txt

!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
!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)
Replace the paragraph:
To raise an exception is to raise a new occurrence of that exception, as explained in 11.4. For the execution of a raise_statement with an exception_name, the named exception is raised. 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 again.
by:
To raise an exception is to raise a new occurrence of that exception, as explained in 11.4. 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 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 again.
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 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 statically within the default_expression for a formal parameter used in a call statically within the predicate.
!corrigendum 13.9.2(2)
Replace the paragraph:
For a prefix X that denotes a scalar object (after any implicit dereference), the following attribute is defined:
by:
For a prefix X that denotes a scalar object (after any implicit dereference) of nominal subtype S, the following attribute is defined:
!corrigendum 13.9.2(3/3)
Replace the paragraph:
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 evaluates to True. The value of this attribute is of the predefined type Boolean.
by:
X'Valid
Yields True if and only if the object denoted by X is normal, has a valid representation, and the membership test "X in S" 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.)

****************************************************************

Questions? Ask the ACAA Technical Agent