Version 1.9 of ai05s/ai05-0188-1.txt

Unformatted version of ai05s/ai05-0188-1.txt version 1.9
Other versions for file ai05s/ai05-0188-1.txt

!standard 4.5.7(0)          10-07-26 AI05-0188-1/06
!standard 4.5.8(0)
!standard 4.9(12)
!standard 4.9(33)
!class amendment 09-11-03
!status Amendment 2012 10-07-26
!status work item 09-11-03
!status received 09-11-03
!priority Low
!difficulty Medium
!subject Case expressions
!summary
case expressions are added to Ada.
!problem
Conditional expressions are added by AI05-0147-1. This proposal is to add an analogous contruct -- the case expression. We also change the name conditional_expression to if_expression, and use conditional_expression to refer to both if_expression and case_expression.
The full coverage rules for case statements and aggregates are a huge benefit to maintenance of Ada programs: If you add an enumeration literal, the compiler tells you about all the case statements and aggregates that need to be modified (assuming you don't defeat the full coverage rules by using "others").
In cases where if_expressions are useful, we don't want to lose the benefits of full coverage rules. A common example is in preconditions. Suppose we have:
procedure Add_To_Fruit_Salad( -- In a package spec. Fruit : in out Fruit_Type; Bowl : in out Bowl_Type);
procedure Add_To_Fruit_Salad( -- In the body. Fruit : in out Fruit_Type; Bowl : in out Bowl_Type) is begin -- Check if ready to add to fruit salad case Fruit.Kind is when Apple => pragma Assert(Fruit.Is_Crisp); null; when Banana => pragma Assert(Fruit.Is_Peeled); null; when Pineapple => pragma Assert(Fruit.Is_Cored); null; end case; Cut_Up(Fruit); Add_To_Bowl(Fruit, Bowl); end Add_To_Fruit_Salad;
We would like to remove those Assert pragmas, and make them into preconditions:
procedure Add_To_Fruit_Salad( Fruit : in out Fruit_Type; Bowl : in out Bowl_Type) with Pre => (if Fruit.Kind = Apple then Fruit.Is_Crisp elsif Fruit.Kind = Banana then Fruit.Is_Peeled elsif Fruit.Kind = Pineapple then Fruit.Is_Cored);
But then if we add Orange to the Fruit_Kind type, we might be missing a precondition. It would be better to write it like this:
procedure Add_To_Fruit_Salad( Fruit : in out Fruit_Type; Bowl : in out Bowl_Type) with Pre => (case Fruit.Kind is when Apple => Fruit.Is_Crisp, when Banana => Fruit.Is_Peeled, when Pineapple => Fruit.Is_Cored);
Now if we add Orange, we will get an error, prompting us to add "when Orange => Fruit.Is_Juicy", or "when Orange => True", or whatever is appropriate.
Without case expressions, we are left with a nasty choice: put the assertions in the body, where they don't belong, or lose the full coverage rules.
!proposal
(See wording.)
!wording
Rename 4.5.7 as added by AI05-0147-1 to If Expressions
Modify the syntax rules in 4.5.7 added by AI05-0147-1:
Change conditional_expression to if_expression. Add:
conditional_expression ::= if_expression | case_expression
In 4.5.7, change conditional_expression to if_expression in: * The third paragraph of the Legality Rules; and * All of the Dynamic Semantics rules.
Replace the introduction of 4.5.7 with:
A conditional_expression selects for evaluation at most one of the enclosed dependent_expressions, depending on some form of condition. One kind of conditional_expression is the if_expression, which selects for evaluation a dependent_expression depending on the value of one or more corresponding conditions. Another kind of conditional_expression is defined in 4.5.8.
Add a new clause:
4.5.8 Case expressions
One kind of conditional_expression is the case_expression, which selects for evaluation one of a number of alternative expressions; the chosen alternative is defined by the value of a selector_expression.
Syntax
case_expression ::= (case *selector_*expression is case_expression_alternative {, case_expression_alternative} )
[Editor's note: "selector_" here is a last minute readability change (especially needed for 4.9(12)). I also considered "choosing_" (which just seems weird even if consistent with "choices"), "deciding_" (also weird), "case_" (which gives the same name as the expression as a whole, too confusing), "determining_", and "selecting_". Without this, the wording about choice expressions and this expression just gets too confusing. I do worry about confusion with select statements, although the word selector is used only once relating to such statements.
Probably, a similar change should be made to 5.4 (paragraphs 2, 4, 5, 6, 7, 8, 9, 11, and 12, AARM 10.b and 10.d). This would avoid confusion with the expression in paragraph 5, and make it crystal-clear which rules are referred to by the last paragraph of the Name Resolution Rules below.]
case_expression_alternative ::= when discrete_choice_list => *dependent*_expression
Name Resolution Rules
Redundant[Name Resolution Rules for the type of the case_expression as a whole and the types of the dependent_expressions are given in 4.5.7.]
AARM Proof: A case_expression is a special case of a conditional_expression, so the rules defined for conditional_expressions also apply to case_expressions.
The expected type for the selector_expression and the discrete_choices are as for case statements (see 5.4).
Legality Rules
The expressions and discrete_ranges given as discrete_choices of a case_expression shall be static. Redundant[A discrete_choice others, if present, shall appear alone and in the last discrete_choice_list.]
The possible values of the selector_expression shall be covered as for case statements (see 5.4).
As for case statements, two distinct discrete_choices of a case_expression shall not cover the same value.
Redundant[In addition, Legality Rules that apply to all conditional_expressions (see 4.5.7) apply to case_expressions.]
AARM Proof: A case_expression is a special case of a conditional_expression.
Dynamic Semantics
For the execution of a case_expression, the selector_expression is first evaluated.
If the value of the selector_expression is covered by the discrete_choice_list of some case_expression_alternative, then the dependent_expression of the case_expression_alternative is evaluated, converted to the type of the case_expression, and the resulting value is the value of the case_expression.
Otherwise (the value is not covered by any discrete_choice_list, perhaps due to being outside the base range), Constraint_Error is raised.
================
In 4.9(12.1/3) as added by AI05-0147-1, add "selector_expression".
AI05-0147-1 calls for the replacement of 4.9(33). Add one more bullet:
* a *dependent_*expression of a case_expression whose
expression is static and not covered by the corresponding discrete_choice_list.
The existing bullet is changed to discuss if_expressions rather than conditional_expression.
!discussion
(See !problem.)
!examples
(See !problem.)
!ACATS test
ACATS B and C tests are needed.
!corrigendum 4.5.7
Insert new clause:
Force a conflict: the real text is in the conflict file.
!corrigendum 4.5.8
Insert new clause:
One kind of conditional_expression is the case_expression, which selects for evaluation one of a number of alternative expressions; the chosen alternative is defined by the value of a selector_expression.
Syntax
case_expression ::= case selector_expression is case_expression_alternative {, case_expression_alternative}
case_expression_alternative ::= when discrete_choice_list => dependent_expression
Name Resolution Rules
Name Resolution Rules for the type of the case_expression as a whole and the types of the selector_expressions are given in 4.5.7.
The expected type for the selector_expression and the discrete_choices are as for case statements (see 5.4).
Legality Rules
The expressions and discrete_ranges given as discrete_choices of a case_expression shall be static. A discrete_choice others, if present, shall appear alone and in the last discrete_choice_list.
The possible values of the selector_expression shall be covered as for case statements (see 5.4).
As for case statements, two distinct discrete_choices of a case_expression shall not cover the same value.
In addition, Legality Rules that apply to all conditional_expressions (see 4.5.7) apply to case_expressions.
Dynamic Semantics
For the execution of a case_expression, the selector_expression is first evaluated.
If the value of the selector_expression is covered by the discrete_choice_list of some case_expression_alternative, then the dependent_expression of the case_expression_alternative is evaluated, converted to the type of the case_expression, and the resulting value is the value of the case_expression.
Otherwise (the value is not covered by any discrete_choice_list, perhaps due to being outside the base range), Constraint_Error is raised.
!corrigendum 4.9(12)
Insert after the paragraph:
!corrigendum 4.9(33)
Replace the paragraph:
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:
by:
An expression is statically unevaluated if it is part of:
Rest of the wording is found in the conflict file.
!appendix

From: Bob Duff
Sent: Tuesday, November 3, 2009  1:10 PM

Here's an AI on case expressions, to complement conditional expressions.

[This is version /01 of the AI - ED]

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

From: Robert Dewar
Sent: Tuesday, November 3, 2009  1:19 PM

> Case expressions are added to Ada.

looks good to me, I am going to go ahead and implement this in GNAT

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

From: Pascal Leroy
Sent: Monday, November 16, 2009  3:53 PM

>  procedure Add_To_Fruit_Salad(
>     Fruit : in out Fruit_Type; Bowl : in out Bowl_Type)
>     with
>       Pre =>
>         (case Fruit.Kind is
>            when Apple => Fruit.Is_Crisp,
>            when Banana => Fruit.Is_Peeled,
>            when Pineapple => Fruit.Is_Cored);

At first I liked the if-expressions: I have often wanted them, and had to
simulate them with ugly work-arounds involving Boolean'Pos and the like.  Then
of course I see the point about having a case-expression where you have the
benefits of the coverage rules, and you preserve the symmetry among the choices.

I am starting to feel uncomfortable, though, because there is no telling where
this will stop.  Why not loop-expressions, for instance?

procedure P (S : String)
   with Pre => (for I in S'Range loop if S(I) > 'a' then false);

Also, if you have a bunch of subprograms that all have the same pre- or
post-conditions, are you going to repeat the same expression over and over
again?  It seems to me that it's virtually impossible to reuse pre- and
post-conditions.  That's not good.  As Bob likes to point out, the subprogram is
the fundamental unit of code reuse, and it's unfortunate to have to give up on
it.  What I would really like to write is something like:

function Fruit_Is_Ready (Fruit : Fruit_Type) return Boolean renames -- Or whatever syntax.
     (case Fruit.Kind is
            when Apple => Fruit.Is_Crisp,
            when Banana => Fruit.Is_Peeled,
            when Pineapple => Fruit.Is_Cored);

procedure Add_To_Fruit_Salad(
     Fruit : in out Fruit_Type; Bowl : in out Bowl_Type)
     with
       Pre => Fruit_Is_Ready(Fruit);

Of course, this would probably be more complicated to describe and to
implement...

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

From: Randy Brukardt
Sent: Monday, November 16, 2009  4:06 PM

...
>	I am starting to feel uncomfortable, though, because there is  no
>telling where this will stop.  Why not loop-expressions, for instance?

That's AI05-0176-1 (Quantified expressions). Thank Ed for that one.

>	Also, if you have a bunch of subprograms that all have the same
> pre- or post-conditions, are you going to repeat the same expression
>over and over again?  It seems to me that it's virtually impossible to
>reuse pre- and post-conditions.  That's not good.  As Bob likes to
>point  out, the subprogram is the fundamental unit of code reuse, and
>it's  unfortunate to have to give up on it.  What I would really like
>to write>  is something like:
>
>	function Fruit_Is_Ready (Fruit : Fruit_Type) return Boolean renames
-- Or whatever syntax.
>	     (case Fruit.Kind is
>	            when Apple => Fruit.Is_Crisp,
>	            when Banana => Fruit.Is_Peeled,
>	            when Pineapple => Fruit.Is_Cored);

That's AI05-0177-1, renaming of expressions as functions. Thank me for pushing
this idea (although I think it might have been yours originally, many years
ago).

>	Of course, this would probably be more complicated to describe and
>  to implement...

Not really; it's the same as default expressions; the resolution is the same as
preconditions. Both of those are already done.

Anyway, is there any concern here that is not already on the agenda?? :-)

It certainly is true that this creeping featurism is what is worrying me, and
Bob, and several others. We'll probably have to do some work to reign that in.
But at this stage, it is more important to have all of the ideas on table so we
can weight them properly.

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

From: Robert Dewar
Sent: Monday, November 16, 2009  4:09 PM

> I am starting to feel uncomfortable, though, because there is no
> telling where this will stop.  Why not loop-expressions, for instance?
>
> procedure P (S : String)
>    with Pre => (for I in S'Range loop if S(I) > 'a' then false);

Well indeed, this is the case of quantifiers, which are being actively
considered, and indeed go along with the other forms.

> function Fruit_Is_Ready (Fruit : Fruit_Type) return Boolean renames --
> Or whatever syntax.
>      (case Fruit.Kind is
>             when Apple => Fruit.Is_Crisp,
>             when Banana => Fruit.Is_Peeled,
>             when Pineapple => Fruit.Is_Cored);
>
> procedure Add_To_Fruit_Salad(
>      Fruit : in out Fruit_Type; Bowl : in out Bowl_Type)
>      with
>        Pre => Fruit_Is_Ready(Fruit);
>
> Of course, this would probably be more complicated to describe and to
> implement...

I'm a bit confused, I don't quite understand your suggested syntax here, but
most certainly functional abstraction is possible in pre and post conditions.

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

From: Jean-Pierre Rosen
Sent: Monday, November 16, 2009  4:51 PM

> It certainly is true that this creeping featurism is what is worrying
> me, and Bob, and several others.

Count me in

> We'll probably have to do some work to reign that in. But at this
> stage, it is more important to have all of the ideas on table so we
> can weight them properly.

Hmmm... Time for a "zero based budget" ?

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

From: Bob Duff
Sent: Monday, November 16, 2009  4:57 PM

> It certainly is true that this creeping featurism is what is worrying
> me, and Bob, and several others.

Yeah, but I notice that we don't all agree on which of those creeps should be
squelched.  E.g. I find case expressions significantly more useful than the +:=
thing, and not that much more difficult to implement.

I don't even agree with myself from week to week.  ;-)

I think there's a lot on the table, though not as much as for Ada 2005.

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

From: Robert Dewar
Sent: Monday, November 16, 2009  5:09 PM

>> It certainly is true that this creeping featurism is what is worrying
>> me, and Bob, and several others.
>
> Yeah, but I notice that we don't all agree on which of those creeps
> should be squelched.  E.g. I find case expressions significantly more
> useful than the +:= thing, and not that much more difficult to implement.

Well not from where I sit. Case expressions is more like a days work, the +:= is
more like an hour or two, but still in the very easy category.

> I don't even agree with myself from week to week.  ;-)
>
> I think there's a lot on the table, though not as much as for Ada 2005.

Well I am the first to get worried about an excessive implementation burden, or
gratuitous upward incompatibilities (we still have customers staying away from
Ada 2005, perhaps for ever, because of the limited return imcompatibility). But
so far the 2012 changes proposed seem very much in reasonable range (I have not
seen the real time stuff, which is effectively optional anyway).

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

From: Pascal Leroy
Sent: Tuesday, November 17, 2009  12:56 AM

> Anyway, is there any concern here that is not already on the agenda?? :-)

Sorry for missing that this stuff was already being worked on.  I have a hard
time keeping track of all the ideas that are thrown around.  And I certainly
don't have a "big picture" of where this Amendment is going.

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

From: Edmond Schonberg
Sent: Tuesday, November 17, 2009  12:05 PM

> Anyway, is there any concern here that is not already on the agenda??
> :-)
>
> Sorry for missing that this stuff was already being worked on.  I have
> a hard time keeping track of all the ideas that are thrown around.
> And I certainly don't have a "big picture" of where this Amendment is
> going.

It is going in the direction of safety, of course!  That means that
pre/postconditions and type invariants are the most significant additions. To
support these there is a new syntax for aspects of entities, and it follows that
there is also improved syntax for predicates of various sorts: if-expressions,
case expressions, quantified expressions.  Then (perhaps) there are new forms of
constraints and non-contiguous discrete subtypes. More routine additions include
new container types.

New syntax for assignment operations is way down the list compared with the
above, in my opinion.

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

From: Bob Duff
Sent: Wednesday, February 3, 2010  4:26 PM

Here's my homework on AI05-0188-1 Case expressions.

Minor changes to !problem, major changes to !wording.

[This is version /03 of the AI - Editor.]

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

From: Tucker Taft
Sent: Wednesday, February 3, 2010  4:35 PM

Might you consider defining:

   conditional_expression ::= if_expression | case_expression

   if_expression ::= IF ...

   case_expression ::= CASE ...

This would seem more consistent, and would eliminate the awkward
"conditional_expression or case_expression" appearing all over the place.

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

From: Bob Duff
Sent: Wednesday, February 3, 2010  5:19 PM

> Might you consider defining:
>
>    conditional_expression ::= if_expression | case_expression
>
>    if_expression ::= IF ...
>
>    case_expression ::= CASE ...

Yes, I might.

> This would seem more consistent, and would eliminate the awkward
> "conditional_expression or case_expression"
> appearing all over the place.

If we could get a concensus that both of these AIs are 'in', then we could
simplify them by combining them, and write the common wording stuff just once.

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

From: Bob Duff
Sent: Wednesday, February 3, 2010  4:28 PM

The proposed syntax for case expressions separates alternatives with commas.
Robert thinks perhaps we should leave them out -- not sure. Comments?  I am
(mildly) in favor of keeping the commas.

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

From: Robert Dewar
Sent: Wednesday, February 3, 2010  4:32 PM

I am not sure I like the commas, though that's what I have implemented for now,
consider

    A := (if    X = Red   then 3
          elsif X = Green then 4
          elsif X = Blue  then 5
          else                 6);

    A := (case X is
          when Red   => 3,
          when Green => 4,
          when Blue  => 5,
          others     => 6);

Or should we try to have a more parallel syntax

    A := (case X is
          when Red   => 3
          when Green => 4
          when Blue  => 5
          others     => 6);

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

From: Tucker Taft
Sent: Wednesday, February 3, 2010  4:40 PM

I prefer the commas.  I don't think everyone is going to format their output the
way you have here, and it looks better to me to have commas when formatted as
follows:

    (case X is when A => 5, when B => 6, when others => 7)

If it were "else when" then I could see dropping the commas, but "when A => 5
when B => 6" is harder to read without the commas in my view.

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

From: Robert Dewar
Sent: Wednesday, February 3, 2010  4:49 PM

OK, commas fine by me (and less implementation work for sure at this stage,
since already done).

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

From: Gary Dismukes
Sent: Wednesday, February 3, 2010  5:40 PM

> Minor changes to !problem, major changes to !wording.

Looks good.

One spelling nit:

> Whereever the Syntax Rules allow an expression,

Whereever => Wherever

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

From: Bob Duff
Sent: Wednesday, February 3, 2010  6:38 PM

Randy, do you take care of this sort of editorial thing?

Anyway, note that this typo was copied from AI-147, so should be fixed in both.
Unless we combine them!

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

From: Randy Brukardt
Sent: Wednesday, February 3, 2010  7:56 PM

I'll take care of it.

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

From: Randy Brukardt
Sent: Wednesday, February 3, 2010  8:21 PM

...
> Add a bullet following 4.3.3(14):
>
> * For a conditional_expression or case_expression, the applicable index
>   constraint for each *dependent_*expression is that, if any, defined
>   for the conditional or case_expression;
>
> (Minor detail: AI05-0147-1 suggests this should go after (15), but it
> seems better after (14).)

I put it after (15) because these are semantically parenthesized expressions,
and as such, it seemed best to group them with it (and after it). I did that
consistently (for instance, in the wording for limited expressions). Not a big
deal either way.

...
> Modify 7.5(2.1/2):
>
> In the following contexts, an expression of a limited type is not
> permitted unless it is an aggregate, a function_call, [or ]a
> parenthesized expression or qualified_expression whose operand is
> permitted by this rule{, or a conditional_ or case_expression all of
> whose *dependent_*expressions are permitted by this rule}:
>
> AARM Note: There is nothing corresponding to the implicit "else False"
> for conditional_expressions.

This AARM note seems to be in the wrong place; I can't imagine what it has to do
with expressions of limited types. But it might make sense somewhere in 4.5.8.

Tucker later writes:

> Might you consider defining:
>
>   conditional_expression ::= if_expression | case_expression
>
>   if_expression ::= IF ...
>
>   case_expression ::= CASE ...
>
> This would seem more consistent, and would eliminate the awkward
"conditional_expression or
> case_expression" appearing all over the place.

That would be OK, but I would object to combining the sections for the kinds of
expressions. We keep the legality and semantic rules for case and if statements
separate, and I would think we want to do that here as well.

I also have to wonder if this solution works very well for
quantified_expressions, which also have to be referred to in many of these
places (although the semantics is somewhat different). Would it look weird to
combine two of the three new kinds of expressions, and not the third??

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

From: Ed Schonberg
Sent: Wednesday, February 3, 2010  8:30 PM

> I also have to wonder if this solution works very well for
> quantified_expressions, which also have to be referred to in many of
> these places (although the semantics is somewhat different). Would it
> look weird to combine two of the three new kinds of expressions, and
> not the third??

The resolution rules for conditional expressions and case expressions are
similar, but completely different from those of quantified expressions. The
latter are always boolean, and there is nothing in the context that impacts
the resolution of the container expression and the predicate, so they have
to have their own section.

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

From: Randy Brukardt
Sent: Wednesday, February 3, 2010  8:43 PM

One more thing... (unless Steve Jobs has that trademarked :-)

> Bob Duff writes:

>Add after 4.9(12):
>
>* A case_expression all of whose conditions and dependent_expressions are
>  static expressions;

There aren't any conditions in a case_expression, so this is clearly wrong.
There isn't a name for the expression that controls the choice, so we can't
say that here. But I suppose that we don't need to differentiate here:

* A case_expression all of whose expressions are static expressions;

seems to be good enough.

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

From: Bob Duff
Sent: Wednesday, February 24, 2010  2:41 PM

New version of AI05-0188-1, "Case expressions".

I'm not sure this is entirely correct, since it's supposed to depend on
AI05-0147-1, which Tucker has not yet updated.

I am assuming that AI05-0147-1 covers these issues, with wording that still
works for this AI (AI05-0188-1).

    - applicable index constraint

    - Wording similar to this:

        Modify 4.4(1) to add conditional_expressions, as follows:

        In this International Standard, the term "expression" refers to a
	construct of the syntactic category expression or of any of the
	following categories: relation, simple_expression, term, factor,
	primary, conditional_expression.

    - Wherever the Syntax Rules allow an expression, a case_expression may be
      used in place of the expression, so long as it is immediately surrounded
      by parentheses.

      [AARM: Note that the above is the same rule as for conditional_expressions;
      see 4.5.7 for further discussion.]

    - Static expressions (4.9(12, 33)):

    - 7.5(2.1/2) -- "In the following contexts, an expression of a limited type
      is not permitted unless...."

[Following was version /04 of this AI - Editor.]

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

From: Steve Baird
Sent: Wednesday, February 24, 2010  5:00 PM

> If a case_expression is expected to be of a type T, the expected type
> for each *dependent_*expression of the case_expression is T. If a
> case_expression shall resolve to a type T, each dependent_expression shall resolve to T.
>

The corresponding wording for if_expressions (formerly
conditional_expressions) has a TBH note because it was decided that saying what
we really mean here is too much trouble. (Just to recap, I'm referring to the
interaction between this wording and, e.g., the rule for qualified expressions
(4.7(3)) or for conditions (5.3(4))).

Don't we need to do that again here?

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

From: Bob Duff
Sent: Wednesday, February 24, 2010  5:50 PM

Yeah, or better yet, make sure the if_expr AI is worded in a way that obviates
the need for duplicating the wording for case_exprs.  That's Tuck's job.

I was told to make the case_expr AI depend on the if_expr AI, but not the other
way 'round.  But the if_expr AI needs to "secretly" depend on the case_expr AI,
in the sense that the wording has to be carefully crafted to cover case_exprs.

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

From: Randy Brukardt
Sent: Wednesday, February 24, 2010  6:02 PM

...
>Yeah, or better yet, make sure the if_expr AI is worded in a way that
>obviates the need for duplicating the wording for case_exprs.  That's
Tuck's job.

Bob, there is no open homework on AI05-0147-1. It's (supposedly) finished as I
posted it (sometime after Feb 4). I believe I extracted the needed wording from
Tuck right after the last meeting.

So if there is something that needs to be changed about it, please tell us.

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

From: Randy Brukardt
Sent: Wednesday, February 24, 2010  9:27 PM

>     - Static expressions (4.9(12, 33)):

4.9(33) is about unselected branches in if_expressions. That depends on the
definition of "condition" and the execution of if statements. That wording
cannot be made to work for case expressions, because the terminology for the two
kinds of statements is completely different (you have to use something about
"covers"). I left that wording in the draft!

We need some wording in here to say that 4.5.7 as added by AI-147-1 is renamed
to If expressions, and all uses of conditional_expression in Legality Rules,
Static Semantics, and Dynamic Semantics are changed to if_expression. I added
that.

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

From: Steve Baird
Sent: Monday, August 2, 2010  6:20 PM

In discussions with Randy, we have run into what appear to be some loose ends
pertaining to conditional expressions.

1) We need wording in 6.2 to extend the definition of
    "associated object" to handle conditional expressions.
    This looks easy to fix.

2) 6.5(5.6/3) seems to be a redundant copy of 7.5(2.8/2)
    which didn't get updated. Rather than update it, it
    should probably be deleted. Also easy.

3) Interactions between conditional expressions and
    accessibility levels may need some more thought.
    Or perhaps these have all been thought about and there
    are no problems here - given that AIs 147 and 188 do not
    mention the word "accessibility", this seems unlikely.

    Consider determining the (static) legality of
       T'(<conditional expression>).Aliased_Component'Access

    Is the static accessibility level of the prefix of the
    Access attribute well-defined ? It doesn't seem to be.

    One's first reaction in a case like this should be to ask
    "how are parenthesized expressions handled?". Unfortunately,
    it is not obvious how to generalize 3.10.2(9/2) to handle
    conditional expressions:
        The accessibility level of a view conversion,
        qualified_expression, or parenthesized expression, is the
        same as that of the operand.
    Perhaps we could follow the rules for an aggregate.

    It may be that the dynamic accessibility level of a conditional
    expression is easy to define as that of the selected dependent
    expression, but that idea needs both wording and review.

    6.5 has a legality rule for functions with class-wide results that
    is defined in terms of the accessibility level of the type of
    of the (returned) expression. Does this rule do what we want
    in the case of a conditional expression?

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

From: Tucker Taft
Sent: Monday, August 2, 2010  6:38 PM

I would suggest we say that conditional expressions are not aliased, though if
they are tagged then a formal parameter that denotes a conditional expression is
of course aliased (but very local).

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

From: Randy Brukardt
Sent: Monday, August 2, 2010  7:42 PM

That doesn't help. Steve made a similar argument privately, and that would
surely work for 'Access. But we also have 4.8(5.1/2) and 6.5(5.6/2) [this is
6.5(5.7/3) in the latest RM draft] that test the accessibility of classwide
returns (so that objects of more nested types don't get returned). There are
similar rules for access discriminants (I'm not sure this one can happen, but
the classwide one surely can). In both of those cases, nothing needs to be
aliased to trigger the check.

For instance, using 4.8(5.1/2) as the example, what is the static accessibility
of:

    new T'Class'(if C then A else B)

if A and B have different tagged types at different levels? (The dynamic
accessibility is less of a problem, as we can just use the level of whatever is
actually selected.)

We could say that there is no static level in this case (but that threatens all
of the analysis we've done about dynamic checks not being needed in return
cases, since that analysis assumes that static checks are made). Or we could
define a rule requiring the static checks for all of the dependent_expressions
to pass (but that seems to require changes to 4.8(5.1/2) and 6.5(5.7/3), since I
can't imagine any way to say in 3.10.2 that conditional_expressions have
*multiple* static accessibility levels!). Or we could require that the static
accessibility level of a conditional_expression is calculable by requiring some
relationship (but that seems limiting for a case that will be very rare in
practice). No good answer seems obvious...

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

From: Tucker Taft
Sent: Monday, August 2, 2010  7:57 PM

Perhaps a "simple" equivalence would handle the function return, by saying that
a return of a conditional expression is legal only if a return of each of the
dependent expressions would be legal.

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

From: Steve Baird
Sent: Tuesday, August 3, 2010 11:13 AM

>> I would suggest we say that conditional expressions are not aliased,
>> though if they are tagged then a formal parameter that denotes a
>> conditional expression is of course aliased (but very local).
>
> That doesn't help.

It also doesn't help for another reason. Sure conditional expressions are not
aliased (they don't occur on the list given at the point where the term
"aliased" is defined), but they can have aliased subcomponents.

Note the example in my original message:
> Consider determining the (static) legality of
>       T'(<conditional expression>).Aliased_Component'Access

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

From: Tucker Taft
Sent: Tuesday, August 3, 2010 11:34 AM

Then I would recommend you treat it like a function call or an aggregate, as you
suggested.

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

From: Steve Baird
Sent: Wednesday, August 18, 2010  1:44 PM

I think this is right, but I will point out an issue with this approach which
seems worth mentioning even if we decide to ignore it.

Ideally, I think that it would be desirable to have a conditional expression
with a static selector expression
    if True then <exp1> else <exp2>
be as semantically similar as possible to a parenthesized expression
    (<exp1>)
. As a design principle, we want to avoid subtle differences between
almost-identical things in order to allow program transformations, avoid
confusion, etc.

[Ok, if you really want to get picky to avoid interactions with freezing rules,
assume that exp2 is another copy of exp1 - otherwise exp2 might freeze
something]

3.10.2(9/2) states:
   The accessibility level of a ... parenthesized expression, is the same
   as that of the operand.

To maintain the equivalence that I am asserting is at least somewhat desirable,
we would need to special case either
    1) a conditional expression with a static selector expression or
    2) a conditional expression all of whose dependent expressions have
       the same static accessibility level
or perhaps even a combination of the two (#1 if selector is static, #2
otherwise) in defining the accessibility level of a conditional expression.

On the other hand, perhaps this doesn't matter. How often is a user going to
want to do something like

      Flag : Boolean := ... ; -- non-static
      type R is record F : aliased Integer; end record;
      R1, R2 : R;
      type Ref is access constant Integer;
      Ptr : Ref;
    begin
      Ptr := R'(if Flag then R1 else R2).F'Access;
      declare
          R3 : R;
      begin
          Ptr := R'(if True then R1 else R3).F'Access;

?

The proposed simple, clean "treat it like an aggregate" rule would reject both
of the two Access attribute uses in this example. Is this ok?

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

From: Randy Brukardt
Sent: Wednesday, August 18, 2010  8:22 PM

My initial reaction is that it is not OK. Not so much because of an example like
this, but because of the potential accessibility checks in allocators and return
statements. I would not want to see

     return (if Flag then Obj1 else Obj2);

to become illegal because the objects have different types (or whatever it is
that you are claiming makes the first example illegal; I'm not sure exactly what
rule you are proposing - the "same as an aggregate" would make all accessibility
checks fail as an aggregate is extremely local and that makes no sense at all in
any case where accessibility levels matter).

I thought that we were considering a "runtime check only" for these; it's hard
to imagine any other rule that will work for these (unless we want to do a
static check when all of the operands have the same static level). Any other
rule would be the same as making them illegal in all contexts that require an
accessibility check, and I don't think that is desirable for any of the reasons
that you mentioned at the beginning of your message.

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

From: Steve Baird
Sent: Thursday, August 19, 2010  11:57 AM

> My initial reaction is that it is not OK. Not so much because of an
> example like this, but because of the potential accessibility checks
> in allocators and return statements.

I agree that the example I gave is unimportant. That was my point in asking "how
often is a user going to want to do ... ?".

Your point that it is probably more important to look at scenarios involving
return  statements and allocators is a good one.

To illustrate your point: given a (non-limited) type with an access
discriminant, what is the status of

    function F return Has_Access_Discrim is
    begin
        if ... then
            return Global_Var1; -- OK
        elsif ...
            return Global_Var2; -- OK
        else
            return (if ... then Global_Var1 else Global_Var2); -- ???
        end if;

with respect to the static accessibility check of 6.5(5.7/3) ?

> I would not want to see
>
>      return (if Flag then Obj1 else Obj2);
>
> to become illegal because the objects have different types (or
> whatever it is that you are claiming makes the first example illegal;
> I'm not sure exactly what rule you are proposing - the "same as an
> aggregate" would make all accessibility checks fail as an aggregate is
> extremely local and that makes no sense at all in any case where accessibility levels matter).

I was saying that my example would be illegal because the "same as an aggregate"
rule would cause each conditional expressions to have the accessibility levels
of its enclosing statement, which would make them too short-lived to be
designated by a value of type Ref.

The "same as an aggregate" rule makes sense if the implementation model allows
making a copy. Making a copy is never required; it should be forbidden at least
in the case of a by-reference type (this follows from the definition of
"associated object", which we have already noted requires updating). The
question is whether making a copy should be forbidden in (some) other cases, as
is implicitly done for parenthesized expressions in 3.10.2(9/2):
   The accessibility level of a ... parenthesized expression, is the
   same as that of the operand.
This rule, in effect, forbids making a copy in at least some cases where the
accessibility level matters, such as

    Global_Ptr := T'((Global_Var)).Aliased_Component'Access

Note that we don't want to forbid copying in all cases (e.g., a dependent
expression which is a slice of a packed array of Booleans), but this is not a
problem because accessibility levels don't matter in these cases (just as for a
parenthesized expression whose operand is such a slice).

> I thought that we were considering a "runtime check only" for these;
> it's hard to imagine any other rule that will work for these (unless
> we want to do a static check when all of the operands have the same
> static level). Any other rule would be the same as making them illegal
> in all contexts that require an accessibility check, and I don't think
> that is desirable for any of the reasons that you mentioned at the beginning of your message.

I don't understand what you are suggesting. Could you suggest wording, or at
least be more specific?

I could imagine a legality rule that the static accessibility levels of the
dependent expressions must be pairwise comparable (as opposed to equal). The
(static) accessibility level of the conditional expression could then be defined
to be that of its most short-lived dependent expression.

Please remind me of the status of AIs 147 and 188.
Do we need a new AI to discuss this stuff?

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

From: Randy Brukardt
Sent: Thursday, August 19, 2010  1:30 PM

...
> Note that we don't want to forbid copying in all cases (e.g., a
> dependent expression which is a slice of a packed array of Booleans),
> but this is not a problem because accessibility levels don't matter in
> these cases (just as for a parenthesized expression whose operand is
> such a slice).

I didn't think we wanted to allow making a copy. It surely would screw up
limited types and build-in-place (which we do allow for conditional
expressions).

> > I thought that we were considering a "runtime check only" for these;
> > it's hard to imagine any other rule that will work for these (unless
> > we want to do a static check when all of the operands have the same
> > static level). Any other rule would be the same as making them
> > illegal in all contexts that require an accessibility check, and I
> > don't think that is desirable for any of the reasons that you
> > mentioned at the beginning of your message.
>
> I don't understand what you are suggesting. Could you suggest wording,
> or at least be more specific?

Wording for accessibility rules? Have you lost your mind? ;-) I don't want to
spend three days on this, that's your assignment.

I was suggesting something along the lines of:

If the static accessibility levels of the dependent_expressions are all the
same, the static accessibility level of the conditional_expression is that
level. Otherwise, the conditional_expression does not have a static level (the
dynamic accessibility checks will take care of it).

The only problem with this is that it might invalidate the analysis which
"proved" no need for runtime overhead for aliased and tagged parameters (we
don't want to have to pass dynamic accessibility levels with them; the entire
point is to eliminate that runtime hazard from programs). The reason that's a
problem is that the analysis depends on the static check rejecting any cases
where the dynamic check could fail; if there is a way to "strip" the static
check, then the dynamic check has to be made and it requires passing levels with
parameters.

> I could imagine a legality rule that the static accessibility levels
> of the dependent expressions must be pairwise comparable (as opposed
> to equal). The (static) accessibility level of the conditional
> expression could then be defined to be that of its most short-lived
> dependent expression.

That's probably a better idea than the above.

> Please remind me of the status of AIs 147 and 188.
> Do we need a new AI to discuss this stuff?

AI-147 was approved, but AI-188 was not. So we could put any new rules in
AI-188 - it already makes changes to AI-147 (I'll file this thread onto that
AI.) It would be nice to have this worked out before the October meeting,
though.

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

From: Steve Baird
Sent: Thursday, August 19, 2010  2:31 PM

>> Making a copy ... should be forbidden at least in the case of a
>> by-reference type (this follows from the definition of "associated
>> object", which we have already noted requires updating).

> I didn't think we wanted to allow making a copy. It surely would screw
> up limited types and build-in-place (which we do allow for conditional
> expressions).

A type for which build-in-place is required is always a by-reference type. As
noted earlier, we don't allow copying for those.

And we pretty much have to allow copying for elementary types.

It's those composite but not by-reference types that are the question.
I feel that the existing rules for parenthesized expressions should be used as
guidelines in resolving this.

> Wording for accessibility rules? Have you lost your mind? ;-) I don't
> want to spend three days on this, that's your assignment.

It was worth a try ...

> I was suggesting something along the lines of:
>
> If the static accessibility levels of the dependent_expressions are
> all the same, the static accessibility level of the
> conditional_expression is that level. Otherwise, the
> conditional_expression does not have a static level (the dynamic accessibility checks will take care of it).

"Does not have a static level" would break lots of rules which assume that every
object has a well-defined accessibility level. Perhaps you want something along
the lines of 3.10.2 (13.1/2)'s
    The accessibility level of <blah blah> is deeper than that of
    any master; all such <blah blah>s have this same level.
?

>  It would be nice to have this worked out before the October meeting,

Agreed.

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

From: Randy Brukardt
Sent: Thursday, August 19, 2010  4:04 PM

> "Does not have a static level" would break lots of rules which assume
> that every object has a well-defined accessibility level.

I don't think this is a real problem; access parameters don't have static levels
(for one example). Static levels are defined only for a subset of objects. I'd
be more worried about losing the assumption that composite parameters (to take
one example) always have a static level.

>Perhaps you want something along the
> lines of 3.10.2 (13.1/2)'s
>     The accessibility level of <blah blah> is deeper than that of
>     any master; all such <blah blah>s have this same level.
> ?

Well, that would always cause the static check to fail unless the objects have
the same level; I don't think that is what we want. But we do have to remember
to deal with the case where there is no (useful) static level, as in access
parameters.

BTW, in taking a quick look at 3.10.2, there doesn't seem to be a concept of
static levels, just a static comparison ("statically deeper than") which is not
defined for all objects.

So I would say that the accessibility level of a conditional_expression is that
of the selected dependent_expression (that's obviously dynamic). And then a
bunch of rules to allow "statically deeper than" to be calculated.

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

From: Randy Brukardt
Sent: Friday, August 20, 2010 12:21 AM

...
> I don't think this is a real problem; access parameters don't have
> static levels (for one example). Static levels are defined only for a
> subset of objects. I'd be more worried about losing the assumption
> that composite parameters (to take one example) always have a static
> level.

AI05-0148 says the same applies to stand-alone objects of anonymous
access-to-object types. The following wording is in 3.10.2(19-19.1/3):

* The statically deeper relationship does not apply to the accessibility level
  of the anonymous type of an access parameter specifying an access-to-object
  type; that is, such an accessibility level is not considered to be statically
  deeper, nor statically shallower, than any other.

* The statically deeper relationship does not apply to the accessibility level
  of the type of a stand-alone object of an anonymous access-to-object type;
  that is, such an accessibility level is not considered to be statically
  deeper, nor statically shallower, than any other.

All I was proposing is that the same applies to conditional_expressions if the
dependent_expressions don't have the same static level.

But I think that would break AI-142-4, requiring lots of distributed overhead
for a silly reason. Tucker and I spent a lot of effort proving that:

          return Some_Param.Component'Access;

never needs a dynamic check (and thus there is no overhead to pass a level with
the parameter), because any case which causes trouble is illegal (fails the
static check). But if writing:

          return (if True then Some_Param.Component'Access else null);

gets rid of the static level and requires a dynamic check on the first
dependent_expression, the entire analysis collapses. (It wouldn't surprise me if
that happened in other, older cases as well; I just remember the AI-142-4 one
because it is recent.)

So I think we have to follow your idea of using the statically deepest level of
any of the dependent_expressions (at least of those which have a level,
anonymous parameters and objects don't, and literals don't, either). That might
make some expressions which would work illegal, but the static checks already do
that, and at least one of the dependent_expressions would have to be illegal in
order for the entire expression to be illegal, which seems like enough.

I'll leave wording this as an exercise for the OP (original poster) - Mr. Baird.

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

Questions? Ask the ACAA Technical Agent