Version 1.3 of ai12s/ai12-0062-1.txt

Unformatted version of ai12s/ai12-0062-1.txt version 1.3
Other versions for file ai12s/ai12-0062-1.txt

!standard 11.3(4/2)          13-07-03 AI12-0062-1/02
!class ramification 13-01-31
!status Amendment 202x 13-01-14
!status ARG Approved 9-0-0 13-06-15
!status work item 13-01-31
!status received 13-01-27
!priority Low
!difficulty Easy
!subject Raise exception with failing string function
!summary
If the string expression in a raise_statement or raise_expression itself raises an exception, that exception is propagated (rather than the one named in the raise_statement or expression).
!question
What happens when the string expression in a "raise Excep with String_Func(...)" propagates an exception? Which exception is raised? (The one propagated by String_Func).
!response
11.3(4/2) says:
"If a string_expression is present, the expression is evaluated and its value is associated with the exception occurrence."
This sentence is marked as Redundant, but it's not completely redundant because it is the only text that talks about when the string_expression is evaluated. In any case, "Redundant" is not normative, so this wording controls the effect whether we intended it to or not.
When an expression is evaluated, any exceptions that it might cause are propagated (of course). The above sentence says that happens before the string_expression is associated with the exception occurrence. And that association has to happen before the exception occurrence created by raise statement (or expression) is propagated, because that occurrence isn't fully defined until the value of the message is "associated", and because an occurrence cannot meet the requirements on the exception message of 11.4.1(10.4/3) until the association has happened. In any case, propagating an occurrence that isn't fully initialized is nonsense.
Thus we conclude that the exception raised by string_expression has priority.
This is the preferred response in any case, as it means that a raise_statement and the equivalent call to Ada.Exceptions.Raise_Exception have precisely the same semantics.
!wording
Add a NOTE after 11.3(4/2):
If the evaluation of a string_expression raises an exception, that exception is propagated rather than the one denoted by the exception_name of the raise_statement or raise_expression.
!discussion
None needed.
!corrigendum 11.3(4/2)
Insert after 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.
the new paragraph:
NOTES
1 If the evaluation of a string_expression raises an exception, that exception is propagated rather than the one denoted by the exception_name of the raise_statement or raise_expression.
!ASIS
No ASIS effect.
!ACATS test
An ACATS C-Test could be created to check this, but it would be of low value.
!appendix

From: Tucker Taft
Sent: Sunday, January 27, 2013  5:37 PM

What happens when the string expression in a "raise Excep with String_Func()"
propagates an exception?  Which exception is raised?
The RM doesn't mention this case.

My instinct is to say that we treat the "String_Func()" like an actual parameter
in a hypothetical call on the "Raise_Exception" operation, and follow the normal
rule that if the evaluation of an actual parameter raises an exception, that
that gets propagated, and you never make the enclosing call.

So in this case, I would assume you would not necessarily raise "Excep"
but rather you would propagate whatever exception String_Func() propagates.

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

From: Robert Dewar
Sent: Sunday, January 27, 2013  5:48 PM

I think we should test what existing compilers do, no point in requiring a
change in implementations for this marginal case.

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

From: Erhard Ploedereder
Sent: Monday, January 28, 2013  10:17 AM

> So in this case, I would assume you would not necessarily raise "Excep"
> but rather you would propagate whatever exception String_Func()
> propagates.

I agree. (In particular, what would the exception message be, if Excep were
raised instead?)

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

From: Steve Baird
Sent: Monday, January 28, 2013  11:18 AM

> So in this case, I would assume you would not necessarily raise "Excep"
> but rather you would propagate whatever exception String_Func()
> propagates.

I agree with your instinct.
Even more strongly, I do not see this as a good-arguments-for-both-sides
judgment call (at least after everyone fully understands the issues). I think
there is clearly only one right answer.

As you pointed out in discussing the other alternative (i.e., raising Excep in
the case of the above example),
> Not obvious what happens when you ask for the associated message.

To me, that removes any doubt about how this construct should be handled.

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

From: Robert Dewar
Sent: Monday, January 28, 2013  11:49 PM

One special case, if we have in a predicate expression

    raise Program_Error with bad-string-raises-constraint-error

and we convert this to "return false" in a membership test, then I don't think
we should be forced to raise CE in this case.

BTW, I would have FAR preferred to say for membership predicates that ANY
exception means the predicate is false, it's really HORRIBLE to have a
difference between an explicit raise and a call to a function that does nothing
but a raise. It also has a very simple implementation (the current rule is quite
tricky to implement!)

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

From: Steve Baird
Sent: Monday, January 28, 2013 12:04 PM

> One special case, if we have in a predicate expression
>
>     raise Program_Error with bad-string-raises-constraint-error
>
> and we convert this to "return false" in a membership test, then I
> don't think we should be forced to raise CE in this case.

Agreed.


> BTW, I would have FAR preferred to say for membership predicates that
> ANY exception means the predicate is false, it's really HORRIBLE to
> have a difference between an explicit raise and a call to a function
> that does nothing but a raise. It also has a very simple
> implementation (the current rule is quite tricky to implement!)

I agree with your objections to the solution that was chosen.

I'm a big fan of semantics-preserving transformations. I don't like the idea
that a raise expression of type T is not equivalent to a call to a T-valued
no-separate-spec function which raises the same exception. In the context of a
predicate expression, these two constructs are not equivalent and I don't like
that.

The alternative you describe, however, introduces the possibility of
"swallowing" an exception which was really unintended (and which is raised "far
away"), thereby masking a real error.

The ARG discussed this alternative and viewed it as unacceptable for this
reason.

This one, IMO, is a "good-arguments-on-both-sides" judgment call.

[Editor's note: Discussion on this topic continues in AI12-0063-1.]

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

From: Randy Brukardt
Sent: Monday, January 28, 2013  7:26 PM

To get back to the original question for a moment:

...
> What happens when the string expression in a "raise Excep with
String_Func()"
> propagates an exception?  Which exception is raised?
> The RM doesn't mention this case.

I disagree with the premise that RM doesn't define this case. It's not laid out
with specific wording, but there is no sensible alternative meaning that meets
the requirements of the RM.

Specifically, 11.3 says:

"If a string_expression is present, the expression is evaluated and its value is
associated with the exception occurrence."

[Aside: This sentence is marked as Redundant, but it's not completely redundant
because it is the only text that talks about when the string_expression is
evaluated. In any case, "Redundant" is not normative, so this wording controls
the effect whether we expected it to or not.]

When an expression is evaluated, any exceptions that it might cause are
propagated (of course). But the above sentence, that happens before the
string_expression is associated with the exception occurrence. And that
association has to happen before the exception occurrence created by raise
statement (or expression) is propagated, because that occurrence isn't fully
defined until the value of the message is "associated". Propagating an
incompletely initialized occurrence is nonsense (certainly the Dewar rule would
apply to that), and in any case would violate 11.4.1(10.1/3) (which says that
the message of a raise statement with a string_expression is that of the
provided string -- no exceptions [pun intended] allowed).

Ergo, the language already defines what happens. (Steve noted the problem with
propagating an undefined string but failed to note that the language already has
enough wording to prevent such an outcome -- assuming you don't think that the
language intends to raise an exception with an uninitialized message string
[which is nonsense].)

As a practical matter, I'd be surprised if there are any compilers that do
anything different. In Ada 95, we have the Ada.Exceptions.Raise_Exception
routine, which of course is a normal subprogram call where the parameters
(including the message string) are clearly evaluated first. I'd be stunned if
any Ada 2005 implementation did anything other than use this existing routine to
implement raise statement with string_expression (certainly Janus/Ada does
exactly that). So I think compilers already do what the language says.

Thus, I think this is at most a Ramification; perhaps adding an AARM note would
be of value, but there is absolutely no need to make any normative changes. (And
as Bob often says, we're just as likely to introduce new bugs when we change
wording; we ought to avoid that when there is nothing clearly wrong.)

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

From: Erhard Ploedereder
Sent: Tuesday, January 29, 2013  6:38 AM

> To get back to the original question for a moment:

Thanks, Randy, for bringing the discussion back from the deep end of
non-returning functions of unspecified result type causing Beaujolais and
general Upchuck. :-)

[Editor's note: He's referring to the discussion filed in AI12-0063-1. I'm
sure all of you readers are now rushing to that AI to see what he was
talking about.]

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

From: Jeff Cousins
Sent: Tuesday, January 29, 2013  11:06 AM

I'm not disagreeing that the exception propagated should be that from
String_Func, but the obvious exception message if Excep were to be raised would
be an empty string.  It's quite common for a fault reporting utility to have an
additional information field that is blanked if it fails to obtain any useful
additional information pertaining to the fault. For some one debugging a crash
it would be more useful to propagate Excep than that from String_Func since
closer to identifying the root problem (any exception from String_Func is just
consequential), but it is probably up to the implementor of String_Func to
provide a local exception handler that returns an empty string (maybe saving the
exception occurrence from the internal exception for reporting in a second fault
report) rather than for the language to do anything special.

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

From: Bob Duff
Sent: Tuesday, January 29, 2013  11:26 AM

> I disagree with the premise that RM doesn't define this case. It's not
> laid out with specific wording, but there is no sensible alternative
> meaning that meets the requirements of the RM.

I agree with Randy's analysis.  Whenever we say so-and-so expression is
evaluated, that always means "and it might raise an exception".

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

From: Randy Brukardt
Sent: Tuesday, January 29, 2013  1:44 PM

> I'm not disagreeing that the exception propagated should be that from
> String_Func, but the obvious exception message if Excep were to be
> raised would be an empty string.

Perhaps, but there is absolutely no indication in the RM that that would be an
acceptable result and it would differ from the behavior of the procedure
Raise_Exception. OTOH, the existing wording of the standard seems to confirm
that the exception raised by the message would be propagated. In any case, this
issue is easily solved: don't propagate an exception from a message string! This
isn't something anyone is going to do on purpose; it's caused by a bug in an
error handler and as such the most important thing is that it is well-defined,
not specifically how it is defined.

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

From: Randy Brukardt
Sent: Thursday, January 31, 2013  9:55 PM

In writing up this AI, I had a cross-AI moment that led me to consider a very
Bairdian scenario: what happens if the string expression in a raise_expression
of a predicate raises an exception when it is evaluated in a membership
operation? (Thus combining AI12-0062-1 and AI12-0054-1.)

Having studied the issue, I've concluded that the wording of AI12-0054-1 is
sufficient to define this case:

"...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."

I read this to say that the string_expression is not evaluated (it's not going
to be used), and thus any exception that it would have propagated will not
occur.

I added an AARM note to this effect to AI12-0062-1 to go along with the other
ramification note.

One could make a case that whether the string gets evaluated is unspecified in
the wording above, but I can't imagine any compiler writer wanting to evaluate
something dead, such an exception represents a bug in the string (no one will do
this on purpose), and as such trying to nail it down further is a waste of time
[it's not going to change any user or implementer behavior]. (And I don't want
to risk the wrath of Bob. ;-)

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

From: Robert Dewar
Sent: Thursday, January 31, 2013  9:58 PM

> One could make a case that whether the string gets evaluated is
> unspecified in the wording above, but I can't imagine any compiler
> writer wanting to evaluate something dead, such an exception
> represents a bug in the string (no one will do this on purpose), and
> as such trying to nail it down further is a waste of time [it's not
> going to change any user or implementer behavior]. (And I don't want
> to risk the wrath of Bob. ;-)

IMO, the optimization conditions allow the string to be skipped in any case:

> 5     * An implementation need not always raise an exception when a
>         language-defined check fails. Instead, the operation that failed the
>         check can simply yield an undefined result. The exception need be
>         raised by the implementation only if, in the absence of raising it,
>         the value of this undefined result would have some effect on the
>         external interactions of the program. In determining this, the
>         implementation shall not presume that an undefined result has a value
>         that belongs to its subtype, nor even to the base range of its type,
>         if scalar. Having removed the raise of the exception, the canonical
>         semantics will in general allow the implementation to omit the code
>         for the check, and some or all of the operation itself.

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

From: Randy Brukardt
Sent: Thursday, January 31, 2013  10:14 PM

Quite right. The interesting question really is whether an exception CAN be
raised in such a case. I'm inclined to say no, but it isn't worth putting into
normative wording -- an implementer that prefers to generate dead code even in
the face of an AARM note that says they don't have to is not any more likely to
pay attention to normative wording saying the same. And the case just isn't
important enough to worry about (no one is likely to complain if their buggy
code does something odd).

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

From: Tucker Taft
Sent: Thursday, January 31, 2013  10:15 PM

> ... I read this to say that the string_expression is not evaluated
> (it's not going to be used), and thus any exception that it would have
> propagated will not occur.

I agree, we do not want the string expression evaluated at all when a predicate
is used for a membership test.

> I added an AARM note to this effect to AI12-0062-1 to go along with
> the other ramification note.

That seems adequate, but we might be able to adjust the normative wording a bit
to make it clearer.

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

From: Bob Duff
Sent: Friday, February  1, 2013  8:32 AM

> One could make a case that whether the string gets evaluated is
> unspecified in the wording above, but I can't imagine any compiler
> writer wanting to evaluate something dead, such an exception
> represents a bug in the string (no one will do this on purpose), and
> as such trying to nail it down further is a waste of time [it's not
> going to change any user or implementer behavior]. (And I don't want
> to risk the wrath of Bob. ;-)

Sounds good to me.  ;-)

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

Questions? Ask the ACAA Technical Agent