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

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

!standard 4.5.7(0)          10-06-03 AI05-0188-1/05
!standard 4.5.8(0)
!standard 4.9(33)
!class amendment 09-11-03
!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 the Legality Rules, Static Semantics, and Dynamic Semantics rules of 4.5.7 change conditional_expression to if_expression.
Add a new clause:
4.5.8 Case expressions
A case_expression selects for evaluation one of a number of alternative expressions; the chosen alternative is defined by the value of an expression.
Syntax
case_expression ::= (case expression is case_expression_alternative {, case_expression_alternative} )
case_expression_alternative ::= when discrete_choice_list => *dependent*_expression
Name Resolution Rules
The expected type for the expression and the discrete_choices are as for case statements (see 5.4).
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.
AARM To Be Honest: T in this rule could be any type in a class of types
(including the class of all types), or (for the second rule) an anonymous access type (for renames) or a universal type covering some type (for qualified expressions).
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 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.
If the expected type of a case_expression is any type in a class of types (instead of a particular type), all dependent_expressions of the case_expression shall have the same type.
If the expected type of a case_expression is a specific tagged type, all of the dependent_expressions of the case_expression shall be dynamically tagged, or none shall be dynamically tagged; the case_expression is dynamically tagged if all of the dependent_expressions are dynamically tagged, is tag-indeterminate if all of the dependent_expressions are tag-indeterminant, and is statically tagged otherwise.
AARM Note: There is nothing corresponding to the implicit "else False" for if_expressions.
Dynamic Semantics
For the execution of a case expression, the expression specified after case is first evaluated.
If the value of the expression is covered by the discrete_choice_list of some case_expression_alternative, then the dependent_expression of the _alternative is evaluated, and this 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.
================
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.
!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.

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

Questions? Ask the ACAA Technical Agent