Version 1.17 of ai05s/ai05-0188-1.txt
!standard 3.8.1(15) 11-02-18 AI05-0188-1/11
!standard 3.10.2(9/2)
!standard 3.10.2(32/2)
!standard 4.5.7(0)
!standard 4.9(12)
!standard 4.9(33)
!standard 5.4(2)
!standard 5.4(4)
!standard 5.4(6)
!standard 5.4(7)
!standard 5.4(8)
!standard 5.4(9)
!standard 5.4(11)
!standard 5.4(12)
!standard 6.2(10)
!standard 6.5(5.5/2)
!class amendment 09-11-03
!status Amendment 2012 10-07-26
!status work item 11-02-18
!status ARG Approved 10-0-0 10-10-30
!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 construct -- 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( --
Fruit : in out Fruit_Type; Bowl : in out Bowl_Type);
procedure Add_To_Fruit_Salad( --
Fruit : in out Fruit_Type; Bowl : in out Bowl_Type) is
begin
--
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
Modify 3.8.1(15):
If the discriminant is of a static constrained scalar subtype {and the
discriminated type is not declared in an instance of a generic unit},
then each non-others discrete_choice shall cover only values in that
subtype, and each value of that subtype shall be covered by some
discrete_choice [(either explicitly or by others)];
Immediately following, append the following AARM note:
AARM note:
The exemption for a discriminated type declared in an instance
allows the following example:
declare
generic
type T is new Integer;
package G is
type Rec (Discrim : T) is record
case Discrim is
when -10 .. -1 =>
Foo : Float;
when others =>
null;
end case;
end record;
end G;
package I is new G (Natural); --
begin
null;
end;
Add immediately after 3.10.2(9/2), as a separate bulleted item:
The accessibility level of a conditional_expression is the
accessibility level of the evaluated dependent_expression.
Add after 3.10.2(32):
Legality Rules
An expression is said to have distributed accessibility
if it is
- a conditional_expression (see 4.5.7); or
- a view conversion, qualified_expression, or parenthesized
expression whose operand has distributed accessibility.
The statically deeper relationship does not apply to the
accessibility level of an expression having distributed accessibility;
that is, such an accessibility level is not considered to be
statically deeper, nor statically shallower, than any other.
Any static accessibility requirement that is imposed on an expression
that has distributed accessibility (or on its type) is instead imposed on
the dependent_expressions of the underlying conditional_expression.
This rule is applied recursively if a dependent_expression also
has distributed accessibility.
AARM Discussion:
This means that any Legality Rule requiring that the accessibility
level of an expression (or that of the type of an expression)
shall or shall not be statically deeper than some other level
instead applies, in the case where the expression has distributed
accessibility, to each dependent_expression of the
underlying conditional_expression.
Replace 4.5.7 as added by AI05-0147-1:
A conditional_expression selects for evaluation at most one of the enclosed
dependent_expressions, depending on a decision among the alternatives. 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 the
case_expression, which selects for evaluation one of a number of alternative
dependent_expressions; the chosen alternative is determined by the value of
a selecting_expression.
Syntax
conditional_expression ::= if_expression | case_expression
if_expression ::= if condition then *dependent*_expression
{elsif condition then *dependent*_expression}
[else *dependent*_expression]
condition ::= *boolean_*expression
case_expression ::=
(case *selecting_*expression is
case_expression_alternative {,
case_expression_alternative}
)
case_expression_alternative ::=
when discrete_choice_list =>
*dependent*_expression
Wherever the Syntax Rules allow an expression, a conditional_expression may be
used in place of the expression, so long as it is immediately surrounded by
parentheses.
AARM Notes as in AI05-0147-1.
Name Resolution Rules
If a conditional_expression is expected to be of a type T, then each
dependent_expression of the conditional_expression is expected to be of type T.
Similarly, if a conditional_expression is expected to be of some class of types,
then each dependent_expression of the conditional_expression is subject to the
same expectation. If a conditional_expression shall resolve to be of a type T,
then each dependent_expression shall resolve to be of type T.
The possible types of a conditional_expression are further determined as
follows:
* If the conditional_expression is the operand of a type conversion, the type of
the conditional_expression is the target type of the conversion; otherwise
* If all of the *dependent_*expressions are of the same type, the type of the
conditional_expression is that type; otherwise
* If a *dependent_*expression is of an elementary type, the type of the
conditional_expression shall be covered by that type; otherwise
* If the conditional_expression is expected to be of type T or shall resolve to
type T, then the conditional expression is of type T.
A condition is expected to be of any boolean type.
The expected type for the selecting_expression and the discrete_choices are
as for case statements (see 5.4).
Legality Rules
All of the dependent_expressions shall be convertible (see 4.6) to the type of
the conditional_expression.
If the expected type of a conditional_expression is a specific tagged type, all
of the dependent_expressions of the conditional_expression shall be
dynamically tagged, or none shall be dynamically tagged; the
conditional_expression is dynamically tagged if all of the
dependent_expressions are dynamically tagged, is tag-indeterminate if all of
the dependent_expressions are tag-indeterminate, and is statically tagged
otherwise.
For an if_expression, if there is no "else" dependent_expression, all of the
dependent_expressions of the if_expression shall be of a boolean type.
All Legality Rules that apply to the discrete_choices of a case_statement (see 5.4),
apply to the discrete_choices of a case_expression {which does not occur within
an instance of a generic unit}.
AARM note:
The exemption for a case expression which occurs in an instance
allows the following example:
generic
with function Int_Func return Integer;
package G is
X : Float := (case Int_Func is
when Integer'First .. -1 => -1.0,
when 0 => 0.0,
when Positive => 1.0);
end G;
function Nat_Func return Natural is (123);
package I is new G (Int_Func => Nat_Func); --
Dynamic Semantics
For the evaluation of an if_expression, the condition specified after
if, and any conditions specified after elsif, are evaluated in succession
(treating a final else as elsif True then), until one evaluates to True or
all conditions are evaluated and yield False. If a condition evaluates to
True, the associated dependent_expression is evaluated, converted to the
type of the conditional_expression, and the resulting value is the value of the
if_expression. Otherwise (when there is no else clause), the value
of the if_expression is True.
AARM Ramification: "Else" is required unless the conditional_expression has
a boolean type, so the last sentence can only apply to conditional_expressions
with a boolean type.
For the evaluation of a case_expression, the selecting_expression is
first evaluated. If the value of the selecting_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 "selecting_expression".
AI05-0147-1 calls for the replacement of 4.9(33).
Add one more bullet:
* a *dependent_*expression of a case_expression whose
selecting_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.
Append to the end of 6.2(10):
For a conditional_expression, this object is the one associated with
the evaluated dependent_expression.
Replace 6.5(5.5/2) and AARM 6.5(5.c/2): [Note: This paragraph was renumbered
to 5.6/3 by AI05-0032-1]
If the result subtype of the function is limited, then the expression
of the return statement (if any) shall be an aggregate, a function
call (or equivalent use of an operator), or a qualified_expression or
parenthesized expression whose operand is one of these.5.c/2
Discussion: In other words, if limited, the expression must produce a
“new” object, rather than being the name of a preexisting object
(which would imply copying).
with
Redundant [If the result subtype of the function is limited, then the
expression of the return statement (if any) shall meet the restrictions
described in 7.5.]
===
Replace the first line of 5.4(2) with:
case selecting_expression is
In 5.4(4), 5.4(5), 5.4(6), 5.4(7), 5.4(8), 5.4(9), 5.4(11), 5.4(12), and
AARM 5.4(10.b) and 5.4(10.d), replace "expression" with "selecting_expression".
!discussion
The changes to 3.10.2, 6.2, and 6.5 are needed to close minor holes in the
original AI05-0147-1; they equally apply to this AI.
Defining the accessibility level of a conditional expression to be that of the
evaluated expression may preclude making a copy in some cases. Consider
type R is record F : aliased Integer; end record;
X, Y : R;
type Ref is access constant Integer;
Ptr : Ref;
procedure Foo (Flag : Boolean) is
begin
Ptr := R'(if Flag then X else Y).F'access;
end Foo;
It would be incorrect to assign into Ptr a reference to a copy that will cease
to exist when Foo is exited.
This non-copying is required for an immutably limited type and seems desirable for
a by-reference type, For a conditional expression of a by-copy type or of a
neither-by-copy-nor-by-reference type, the situation seems less clear. However,
the given wording is consistent with the treatment of parenthesized expressions,
qualified expressions, etc. Note also that the accessibility level of a
conditional expression is completely irrelevant in most cases; in those cases,
this rule would have no bearing on whether an implementation would be allowed to
make a copy.
!examples
(See !problem.)
!ACATS test
ACATS B and C tests are needed.
!corrigendum 3.8.1(15)
Replace the paragraph:
- If the discriminant is of a static constrained scalar subtype, then each
non-others discrete_choice shall cover only values in that subtype, and
each value of that subtype shall be covered by some discrete_choice (either
explicitly or by others);
by:
- If the discriminant is of a static constrained scalar subtype and the
discriminated type is not declared in an instance of a generic unit, then each
non-others discrete_choice shall cover only values in that subtype, and
each value of that subtype shall be covered by some discrete_choice (either
explicitly or by others);
!corrigendum 3.10.2(9/2)
Insert after the paragraph:
- The accessibility level of a view conversion, qualified_expression,
or parenthesized expression, is the same as that of the operand.
the new paragraph:
- The accessibility level of a conditional_expression is the
accessibility level of the evaluated dependent_expression.
!corrigendum 3.10.2(32/2)
Insert after the paragraph:
P'Access yields an access value that designates the subprogram
denoted by P. The type of P'Access is an access-to-subprogram
type (S), as determined by the expected type. The accessibility
level of P shall not be statically deeper than that of S. In
addition to the places where Legality Rules normally apply (see
12.3), this rule applies also in the private part of an instance
of a generic unit. The profile of P shall be subtype-conformant
with the designated profile of S, and shall not be Intrinsic.
If the subprogram denoted by P is declared within a generic unit,
and the expression P'Access occurs within the body of that generic
unit or within the body of a generic unit declared within
the declarative region of the generic unit, then the ultimate ancestor
of S shall be either a non-formal type declared within the generic
unit or an anonymous access type of an access parameter.
the new paragraphs:
Legality Rules
An expression is said to have distributed accessibility
if it is
- a conditional_expression (see 4.5.7); or
- a view conversion, qualified_expression, or parenthesized
expression whose operand has distributed accessibility.
The statically deeper relationship does not apply to the
accessibility level of an expression having distributed accessibility;
that is, such an accessibility level is not considered to be
statically deeper, nor statically shallower, than any other.
Any static
accessibility requirement that is imposed on an expression that
has distributed accessibility (or on its type) is instead imposed on
the dependent_expressions of the underlying conditional_expression.
This rule is applied recursively if a dependent_expression also
has distributed accessibility.
!corrigendum 4.5.7
Insert new clause:
Force a conflict: the real text is in the conflict file.
!corrigendum 4.9(12)
Insert after the paragraph:
- a short-circuit control form both of whose relations are static
expressions;
the new paragraph:
- a conditional_expression all of whose conditions and
selecting_expressions are static expressions;
!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.
!corrigendum 5.4(2)
Replace the paragraph:
case_statement ::=
case expression is
case_statement_alternative {,
case_statement_alternative}
end case;
by:
case_statement ::=
case selecting_expression is
case_statement_alternative {,
case_statement_alternative}
end case;
!corrigendum 5.4(4)
Replace the paragraph:
The expression is expected to be of any discrete type.
The expected type for each discrete_choice is the type of the
expression.
by:
The selecting_expression is expected to be of any discrete type.
The expected type for each discrete_choice is the type of the
selecting_expression.
!corrigendum 5.4(6)
Replace the paragraph:
The possible values of the expression shall be
covered as follows:
by:
The possible values of the selecting_expression shall be
covered as follows:
!corrigendum 5.4(7)
Replace the paragraph:
- If the expression is a name (including a
type_conversion or a function_call)
having a static and constrained nominal subtype, or is a
qualified_expression whose subtype_mark denotes a static and
constrained scalar subtype, then each non-others discrete_choice
shall cover only values in that subtype, and each value of that
subtype shall be covered by some discrete_choice
(either explicitly or by others).
by:
- If the selecting_expression is a name (including a
type_conversion or a function_call)
having a static and constrained nominal subtype, or is a
qualified_expression whose subtype_mark denotes a static and
constrained scalar subtype, then each non-others discrete_choice
shall cover only values in that subtype, and each value of that
subtype shall be covered by some discrete_choice
(either explicitly or by others).
!corrigendum 5.4(8)
Replace the paragraph:
- If the type of the expression is
root_integer, universal_integer, or a descendant of a
formal scalar type, then the case_statement shall have
an others discrete_choice.
by:
- If the type of the selecting_expression is
root_integer, universal_integer, or a descendant of a
formal scalar type, then the case_statement shall have
an others discrete_choice.
!corrigendum 5.4(9)
Replace the paragraph:
- Otherwise, each value of the base range of the type of the
expression shall be covered (either explicitly
or by others).
by:
- Otherwise, each value of the base range of the type of the
selecting_expression shall be covered (either explicitly
or by others).
!corrigendum 5.4(11)
Replace the paragraph:
For the execution of a case_statement the
expression is first evaluated.
by:
For the execution of a case_statement the
selecting_expression is first evaluated.
!corrigendum 5.4(12)
Replace the paragraph:
If the value of the expression
is covered by the discrete_choice_list of some
case_statement_alternative, then the
sequence_of_statements of the _alternative is executed.
by:
If the value of the selecting_expression
is covered by the discrete_choice_list of some
case_statement_alternative, then the
sequence_of_statements of the _alternative is executed.
!corrigendum 6.2(10)
Replace the paragraph:
A parameter of a by-reference type is passed by reference. Each value of a
by-reference type has an associated object. For a parenthesized expression,
qualified_expression, or type_conversion, this object is the one associated
with the operand.
by:
A parameter of a by-reference type is passed by reference. Each value of
a by-reference type has an associated
object. For a parenthesized expression, qualified_expression,
or type_conversion, this object is the one associated with the
operand. For a conditional_expression, this object is the one associated
with the evaluated dependent_expression.
!corrigendum 6.5(5.5/2)
Replace the paragraph:
If the result subtype of the function is limited, then the expression of the
return statement (if any) shall be an aggregate, a function call (or
equivalent use of an operator), or a qualified_expression or parenthesized
expression whose operand is one of these.
by:
If the result subtype of the function is limited, then the
expression of the return statement (if any) shall meet the restrictions
described in 7.5.
!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: Friday, March 26, 2010 4:05 PM
If you have a case-expression in a generic package spec which cases on, say, a
formal in-out object of type Integer, it must cover all the Integer values.
If you then instantiate the generic with an object whose subtype is Natural, I
don't think we want to see a legality violation upon rechecking the expanded
spec for the instance.
I think the currently posted wording for the AI would require rejecting such an
example. Or at least it is unclear what this wording
The possible values of the expression shall be
covered as for case statements (see 5.4).
means in this case, because a case statement cannot occur in an expanded
instance spec.
Do we agree that this needs fixing?
****************************************************************
From: Bob Duff
Sent: Friday, March 26, 2010 4:20 PM
Yes.
****************************************************************
From: Randy Brukardt
Sent: Friday, March 26, 2010 6:59 PM
I agree with Bob. The recheck typically used could mean that it would be
impossible to write a legal generic specification for many objects that might be
passed to a generic in out parameter. So it seems we need to think about this
some more.
OTOH, use of generic in out formal parameters is pretty rare. (I don't think
I've ever used one outside of test programs.) So it isn't the end of the world
if this is broken. Which means that we don't want a page and a half of new rules
to deal with this case.
****************************************************************
From: Steve Baird
Sent: Friday, March 26, 2010 9:08 PM
I think it is just a few words to say that this legality rule doesn't apply in
an instance spec, along the lines of 8.3(26/2).
****************************************************************
From: Robert Dewar
Sent: Friday, March 26, 2010 9:18 PM
>> I agree with Bob. ... [but] we don't want a page and a half of new
>> rules to deal with this case.
especially when we know how we want things to work :-)
****************************************************************
From: Bob Duff
Sent: Saturday, March 27, 2010 7:24 AM
> OTOH, use of generic in out formal parameters is pretty rare.
They are, but doesn't the same issue arise in other cases, such as formal 'in's,
and functions (formal or not) returning a formal subtype?
****************************************************************
From: Steve Baird
Sent: Saturday, March 27, 2010 7:42 AM
... and formal functions returning non-formal subtypes .
****************************************************************
From: Bob Duff
Sent: Saturday, March 27, 2010 7:56 AM
Oh, yeah, I had forgotten those aren't required to match (yuck).
****************************************************************
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.
****************************************************************
From: Steve Baird
Sent: Tuesday, October 19, 2010 11:45 AM
[He's commenting on version /07, which he had sent the previous day. - Editor.]
I think we want to replace both occurrences of "each" in the above wording with
"any" and replace the occurrence of "every" in the AARM note with "some".
I think all the legality rules are of the form
"blah1 shall *not* be statically deeper than blah2", so that we want an
"is statically deeper" test to return False in the "mixed" case.
For example, I think we don't want to allow
type Ref is access constant Integer;
type Rec is record F : aliased Integer; end record;
Global : Rec;
Ptr : Ref;
procedure Foo (Flag : Boolean) is
Local : Rec;
begin
Ptr := Rec'(if Flag then Global else Local)'Access;
and I think the wording I proposed yesterday would allow this.
****************************************************************
From: Steve Baird
Sent: Wednesday, February 2, 2011 3:10 PM
> If you have a case-expression in a generic package spec which cases
> on, say, a ormal in-out object of type Integer, it must cover all the Integer values.
>
> If you then instantiate the generic with an object whose subtype is
> Natural, I don't think we want to see a legality violation upon
> rechecking the expanded spec for the instance.
Randy reminded Bob and me that this issue was never resolved.
In subsequent discussions, it was noticed that the same problem already exists
for variant parts, as in
procedure Vp_In_Inst is
generic
type T is new Integer;
package G is
type Rec (Discrim : T) is record
case Discrim is
when -10 .. -1 =>
Foo : Float;
when others =>
null;
end case;
end record;
end G;
package I is new G (Natural); -- legal?
begin
null;
end Vp_In_Inst;
It seems that we ought to treat the two situations (variant parts and case
expresssions) consistently.
One alternative is to do nothing: both the above example and similar examples
involving case expressions would be illegal.
This seems unfriendly (especially for case expressions), but it is well defined.
Alternatively, the following wording changes would allow these constructs to be
accepted:
Add at the end of the 3.8.1 Legality Rules section:
To be honest:
The above rule that "each non-others discrete_choice shall cover only
values in that subtype" does not apply to a discrete_choice which
occurs within an instance of a generic unit.
Similarly, immediately after the existing wording for case expressions,
All Legality Rules that apply to the discrete_choices of a
case_statement (see 5.4), apply to the discrete_choices of a
case_expression.
add
To be honest:
The rule for case statements (see 5.4) that in certain situations,
"... each non-others discrete_choice shall cover only values
in that subtype, ..." does not apply to a discrete_choice which
occurs within an instance of a generic unit.
What do folk think?
If someone dislikes using "To Be Honest" clauses in this way, we could discuss
that as a separate question.
****************************************************************
From: Gary Dismukes
Sent: Wednesday, February 2, 2011 3:34 PM
...
> This seems unfriendly (especially for case expressions), but it is
> well defined.
I agree that it would be unfriendly. I don't think that the error is likely to
be helpful in this case. Why limit functionality in this way for no strong
reason? If such constructs are allowed in bodies, they should also be legal in
specs, I think.
> add
>
> To be honest:
> The rule for case statements (see 5.4) that in certain situations,
> "... each non-others discrete_choice shall cover only values
> in that subtype, ..." does not apply to a discrete_choice which
> occurs within an instance of a generic unit.
>
> What do folk think?
I could live with that, but...
> If someone dislikes using "To Be Honest" clauses in this way, we could
> discuss that as a separate question.
... I'd prefer to have normative text that addresses this.
****************************************************************
From: Tucker Taft
Sent: Wednesday, February 2, 2011 3:42 PM
These don't seem like "to-be-honest"-ish statements.
I don't see this as a big enough
issue to justify any changes. It is also one of those things that could be done
later if people start finding this is a significant problem, since it is only
making illegal programs legal.
The fact that no one has ever encountered this with variant parts in 30 years
makes me a little less worried... ;-)
****************************************************************
From: Steve Baird
Sent: Wednesday, February 2, 2011 3:54 PM
Gary wrote:
> ... I'd prefer to have normative text that addresses this.
Tucker wrote:
> These don't seem like "to-be-honest"-ish statements.
Fine with me.
So if we decide to do anything at all about this problem, we'll use "real"
legality rules.
Tuck advocates doing nothing.
A pragmatic case could be made for treating the two constructs inconsistently.
As Tuck notes, there have never been any complaints about the variant_part
situation. On the other hand, this seems like it might be more of a problem for
case expressions.
So alternatives include
1) Do nothing
2) Add permissive legality wording only for case expressions.
2) Add permissive legality wording for both case expressions and
variant parts.
****************************************************************
From: Tucker Taft
Sent: Wednesday, February 2, 2011 5:12 PM
Are we really convinced it is a good idea to make this change? If a case
expression in the generic spec specifies what should be done with particular
values, and the actual type doesn't have those values, doesn't that sound like
something is awry? Is this that different from initializing a named constant of
the formal type to a particular literal value, when that literal value turns out
to be outside the range of the formal subtype?
****************************************************************
From: Steve Baird
Sent: Wednesday, February 2, 2011 5:31 PM
> Are we really convinced it is a good idea to make this change?
I don't think we've reached a consensus on this point. I think this problem is
worth addressing, at least for case expressions (the only real argument for
messing with variant parts is consistency), but I agree that it is a judgment
call and that taking no action is a reasonable alternative.
You'd prefer to take no action.
Gary said "I agree that it would be unfriendly" to reject the case expressions
we've been discussing.
I'd like to get other opinions.
> If a case expression in the
> generic spec specifies what should be done with particular values, and
> the actual type doesn't have those values, doesn't that sound like
> something is awry?
This seems no worse than calling a function which takes an Integer paremeter and
passing it the value of a variable whose subtype is Natural. The function may
provide all sorts of support for the case where it is passed a negative value
and, for this particular call, that code will never be exercised.
> Is this that
> different from initializing a named constant of the formal type to a
> particular literal value, when that literal value turns out to be
> outside the range of the formal subtype?
Yes, it is different. Now you are talking about a situation where the
instantiator requires functionality which the generic doesn't provide, as
opposed to failing to make use of the full functionality which the generic does
provide.
****************************************************************
From: Bob Duff
Sent: Wednesday, February 2, 2011 6:11 PM
> Are we really convinced it is a good idea to make this change?
In the abstract, it seems like a good idea, to me.
The only negative, to me, is that maybe it's not worth the trouble. Most
variant records, and probably most case expressions, are on regular non-formal
enumeration types.
>... If a case expression in the
> generic spec specifies what should be done with particular values,
>and the actual type doesn't have those values, doesn't that sound like
>something is awry? Is this that different from initializing a named
>constant of the formal type to a particular literal value, when that
>literal value turns out to be outside the range of the formal subtype?
I don't buy that analogy, for the reason Steve gave.
A better analogy is a case statement, which must appear in the generic body, and
can specify nonexistent values in an instance. (In fact, case expressions in
the body will work that way.)
The reason to forbid "when -1" when the subtype is Natural, is that that's
almost certainly a mistake. But in the generic case, you don't KNOW it's
Natural -- it just happens to be in one instance, but other instances might need
that -1 case.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, February 2, 2011 8:22 PM
> In subsequent discussions, it was noticed that the same problem
> already exists for variant parts, as in
...
> What do folk think?
If you had waited for me to answer your original question (which has been
delayed by the need to dig out from 19" of snow that we've gotten since Monday
afternoon, along with the steady 35 MPH wind), you would have already found out
that I think that you've lost your mind. (I should have simply buried your
original question, but I didn't think about it as I was in a hurry to leave
before my car was too buried to move.)
Let me explain the ways:
(1) Using a To Be Honest note to change how legality rules work is completely
insane. TBHs are intended for cases where we say *almost* what we mean, but
leave out some something for clarity. Not for cases where we are changing
the rules from check to not check!
(2) There is almost no similarity between the variant case and the case
expression/statement case. Tucker noted that no one has run into this in 30
years, but he didn't explain why.
A variant like this in a generic body is just short of a pathology. The reason
is that you cannot write any aggregates for such a type. The discriminant of an
aggregate that controls variant components has to be static. But no expression
of a generic formal type can ever be static - a generic formal subtype is never
a static subtype, so there can be no static expressions of such a subtype. Thus
there cannot be any aggregates.
Without aggregates, constructing values of a variant record is a chore -- you
have to declare an object of a constrained subtype and then fill in the
components individually. I can imagine doing that if you need to export such a
type, but not otherwise. So I don't think that there can be many such types in
bodies.
OTOH, it does make sense to export such a type from a generic specification (the
instantiator can create objects freely). In that case, having variants that you
can't use is not likely to be a good thing.
In contrast, a case expression, even when used in a generic specification, is
evaluated there; the instantiator can only access the value of that evaluation
(it never uses the expression in any other way). So it doesn't matter as much
what rules are used.
(3) The primary benefit of case expressions is completeness checking. Indeed,
without that I would have voted against them as an unnecessary frill. But
you have to include an "others" clause for any case statement or expression
of a generic formal type. The effect is to make them much less useful;
meaning that if you have to convert them to if-expressions, this is not
going to cause any less safety in your program.
(4) Darn, after reading 4.9 again, it appears that numeric literals can be
static even if they have a formal subtype. So (2) isn't quite right above.
But note that the operators of a formal subtype are NOT static functions
(4.9(19)), so "-1" is NOT static in this case. (Recall that we don't use the
universal operators if a subtype is expected for an expression, rather we
use the operators of that subtype.)
So the variant in Steve's example is illegal in the generic:
generic
type T is new Integer;
package G is
type Rec (Discrim : T) is record
case Discrim is
when -10 .. -1 =>
Foo : Float;
when others =>
null;
end case;
end record;
end G;
since neither "-10" nor "-1" are static, and that violates 3.8.1(8). The same is
true for case statements and case expressions (5.4(5)). (It might have been
legal in the instance, but you'll never get there.)
Similarly, you can use named numbers in such cases and variants, but not
constants (they're not static, either, in this case, nor is a type conversion
from a static constant of some other type).
So you are very limited in what you can do with such things; essentially you can
only use positive literals.
You could still construct problems, but I find it hard to believe that these are
very common.
Also note that the rules about static expressions would apply in the instance
(4.9(33-37)). Even if you waived the case/variant rules, you'd still have the
possibility of illegal instances because violating one of these rules. That
would be implementation-dependent in the case of the base range rule, which
doesn't seem to be adding anything positive to the language!
To summarize:
It seems to me that there would need to be a lot of rewording to support this
case, it would be clearly harmful for exported types, there is no bad effect
from using an if expression instead of a case expression (no completeness check
is possible anyway), most such case expressions are illegal anyway.
So I think leaving the rules as they are is best.
Note that I wouldn't object strongly to changing this for case
expressions/statements only, but I don't think it is worth the effort.
****************************************************************
From: Steve Baird
Sent: Thursday, February 3, 2011 12:36 PM
> ... I think that you've lost your mind.
As I mentioned earlier, there seems to be general agreement that
1) We don't want to make any changes relating
to variant parts.
2) If we do make a change relating to case expressions,
we want to do it via a first-class legality rule,
not via a TBH note.
Given that I agree with the above and feel that the only remaining question is
whether we should do anything at all for case expressions, do you think that I
need to continue the search for my missing mind?
> The primary benefit of case expressions is completeness checking.
Agreed. I think that there are others-less case expressions that can run afoul
of this problem:
generic
X : in out Integer;
package G is
Inc_X_Towards_Zero : constant Integer :=
(case X is
when Integer'First .. -1 => X + 1,
when 0 => 0,
when 1 .. Integer'Last => X - 1
end case);
end G;
Z : Natural := ...;
package I is new G (Z); -- legal?
Hopefully I got the syntax right, but you get the idea in any case.
> Also note that the rules about static expressions would apply in the
> instance (4.9(33-37)). Even if you waived the case/variant rules,
> you'd still have the possibility of illegal instances because
> violating one of these rules.
You bring up an interesting point.
I'm not proposing this, but this could be used as an argument for modifying the
definition of "statically unevaluated" to handle this case. Right now we have
a dependent_expression of a case_expression whose expression is
static and not covered by the corresponding discrete_choice_list.
This could be somehow generalized so that the "X + 1" expression in the above
example (in the instance, not in the generic) is statically unevaluated.
I say wait until someone complains about this one.
****************************************************************
From: Jean-Pieere Rosen
Sent: Thursday, February 3, 2011 3:20 AM
> Gary said "I agree that it would be unfriendly" to reject the case
> expressions we've been discussing.
>
> I'd like to get other opinions.
>
I side with Gary on this one.
Nothing bad can happen from the instantiation, why reject it?
Note that it is different from the case of a variable when the actual type is
Natural, and the variable is initialized to a negative value: Constraint_Error
has to be raised. And still, the instantiation is allowed.
Does anybody really want to reject a case that works perfectly, while not
rejecting a case which is statically known to raise constraint_Error?
****************************************************************
From: Randy Brukardt
Sent: Thursday, February 3, 2011 3:36 PM
> > ... I think that you've lost your mind.
>
> As I mentioned earlier, there seems to be general agreement that
> 1) We don't want to make any changes relating
> to variant parts.
> 2) If we do make a change relating to case expressions,
> we want to do it via a first-class legality rule,
> not via a TBH note.
>
> Given that I agree with the above and feel that the only remaining
> question is whether we should do anything at all for case expressions,
> do you think that I need to continue the search for my missing mind?
Perhaps it is I who has lost his mind. :-) See below.
> > The primary benefit of case expressions is completeness checking.
>
> Agreed. I think that there are others-less case expressions that can
> run afoul of this problem:
>
> generic
> X : in out Integer;
> package G is
> Inc_X_Towards_Zero : constant Integer :=
> (case X is
> when Integer'First .. -1 => X + 1,
> when 0 => 0,
> when 1 .. Integer'Last => X - 1
> end case);
> end G;
>
> Z : Natural := ...;
>
> package I is new G (Z); -- legal?
>
> Hopefully I got the syntax right, but you get the idea in any case.
Interesting. This example exists because the case choices complete the base
range of the type of the selector expression (the subtype of a formal in out is
never considered static).
I don't much care about formal in outs (they're rarely used). I do care about
the similar cases in generic formal subprograms.
I was concerned that there was a new hole here, but I think it is already
plugged.
subtype Short_Int is Integer range 0 .. 100;
generic
with function Foobar (A : Short_Int) return Short_Int;
package Gen is
Something : constant Boolean :=
(case Foobar (1) is
when 1 .. 100 => True,
when 0 => False); -- (1)
end Gen;
This case expression is illegal, as not all of the values of the base range of
the type of the selector expression are covered. That's because the result
subtype of a formal function is never considered static. That's good, as the
actual could have been
function "-" (Right : in Integer) return Integer;
and it would return "-1" in this case.
I was concerned that there was a way to do this with other sorts of formals (in
particular, parameter subtypes of a formal subprogram), but I can't seem to
construct an example.
...
> This could be somehow generalized so that the "X + 1"
> expression in the above example (in the instance, not in the
> generic) is statically unevaluated.
>
> I say wait until someone complains about this one.
I was just thinking that your mind was leaving you again... :-)
One side thought:
Even if we don't formally adopt a rule saying that there is no recheck here, in
the absence of an ACATS test I wouldn't expect there to be any recheck here.
That's because these rechecks usually take explicit work, and in the absence of
some reminder (either a bug report or an ACATS test), it is rare that they get
implemented. In Janus/Ada specifically, we have to write explicit code for any
rechecks needed. A lot of the time when implementing a new legality rule, we
forgot to handle the recheck (and a good part of the time, no recheck is needed,
which makes even less likely to think of it the next time). Moreover, a lot of
those rechecks require saving information that otherwise would be discarded
(like the exact contents of a default expression in a generic - since we code
share, these have already been code generated and thus have no need -- other
than rechecks -- to be saved).
The net effect is that I suspect that this "recheck" will hardly ever be
implemented (especially as no bug can result from omitting it). That seems like
the best reason for actually making an explicit exception in this case: the
recheck will take a lot of work to implement.
****************************************************************
From: Steve Baird
Sent: Friday, February 18, 2011 2:34 PM
Here is proposed wording for this issue, consistent with the intent agreed upon
earlier today in Tampa.
=====
Modify 3.8.1/15
If the discriminant is of a static constrained scalar subtype {and the
discriminated type is not declared in an instance of a generic unit},
then each non-others discrete_choice shall cover only values in that
subtype, and each value of that subtype shall be covered by some
discrete_choice [(either explicitly or by others)];
Immediately following, append the following AARM note:
AARM note:
The exemption for a discriminated type declared in an instance
allows the following example:
declare
generic
type T is new Integer;
package G is
type Rec (Discrim : T) is record
case Discrim is
when -10 .. -1 =>
Foo : Float;
when others =>
null;
end case;
end record;
end G;
package I is new G (Natural); -- legal
begin
null;
end;
====
Modify the existing wording for case expressions,
All Legality Rules that apply to the discrete_choices of a
case_statement (see 5.4), apply to the discrete_choices of a
case_expression {which does not occur within an instance of
a generic unit}.
Immediately following, append the following AARM note:
AARM note:
The exemption for a case expression which occurs in an instance
allows the following example:
declare
generic
with function Int_Func return Integer;
package G is
X : Float := (case Int_Func is
when Integer'First .. -1 => -1.0,
when 0 => 0.0,
when Positive => 1.0);
end G;
function Nat_Func return Natural is
begin return 123; end Nat_Func;
package I is new G (Int_Func => Nat_Func); -- legal
begin
null;
end;
****************************************************************
Questions? Ask the ACAA Technical Agent