CVS difference for ai05s/ai05-0147-1.txt

Differences between 1.6 and version 1.7
Log of other versions for file ai05s/ai05-0147-1.txt

--- ai05s/ai05-0147-1.txt	2010/01/09 01:31:29	1.6
+++ ai05s/ai05-0147-1.txt	2010/01/19 06:48:18	1.7
@@ -1,10 +1,12 @@
-!standard 4.4 (07)                                10-01-07  AI05-0147-1/05
-!standard 4.5.7 (0)
+!standard 4.4(7)                                    10-01-18  AI05-0147-1/05
+!standard 4.5.7(0)
 !standard 4.7(2)
 !standard 4.7(3)
-!standard 4.7(5)
 !standard 4.9(12)
 !standard 4.9(33)
+!standard 5.3(3)
+!standard 5.3(4)
+!standard 7.5(2.1/2)
 !class amendment 09-03-13
 !status work item 09-03-13
 !status received 09-03-13
@@ -87,21 +89,52 @@
 
 !wording
 
-In 4.4(7), add:
+Replace 4.4(7) by:
 
 primary ::=
    numeric_literal | null | string_literal | aggregate
- | name | allocator | (expression) | conditional_expression
+ | name | allocator | (expression_within_parens)
 
+Add after 4.4(7):
+
+expression_within_parens ::=
+   expression
+ | conditional_expression
+
+If an expression appears directly inside of another set of parentheses,
+an expression_within_parens can be used instead. Redundant[This allows
+the use of a single set of parentheses in such cases.]
+
+AARM Reason: We could have written this as a syntax rule (as we did in
+4.7, for instance), but that would have required rewriting many semantic
+rules that depend on the syntax item expression (for instance, the 3rd,
+4th, and 7th paragraphs in 4.1.1, the 7th and 8th paragraphs of 4.1.4,
+the third paragraph of 4.6, and many more).
+
+AARM Ramification: This rule applies to
+attribute_designator and range_attribute_designator (4.1.4),
+type_conversion (4.6), entry_index (9.5.2), and to single (positional)
+items in  pragma (2.8), discriminant_constraint (3.7.1),
+indexed_component (4.1.1), actual_parameter_part (6.4),
+and generic_actual_part (12.3).
+
+AARM Implementation Note: In order to avoid ambiguity, and preserve the
+ability to do useful error correction, it is recommended that the grammar
+for all of the above productions be modified to reflect this rule. For the
+four productions, replacing expression with expression_within_parens
+in the grammar will have the correct effect; for the latter productions,
+adding a parallel singleton_list ::= ( conditional_expression ) will have
+the correct effect without adding any ambiguity.
+
 Add a new clause:
 
 4.5.7 Conditional expressions
 
     Syntax
 
-conditional_expression ::= (if condition then *dependent*_expression
+conditional_expression ::= if condition then *dependent*_expression
     {elsif condition then *dependent*_expression}
-    [else *dependent*_expression])
+    [else *dependent*_expression]
 
 condition ::= Boolean_expression
 
@@ -109,17 +142,34 @@
 
 A condition is expected to be of any boolean type.
 
-The expected type for a conditional_expression shall be a single
-type. The expected type for each *dependent*_expression of a
-conditional_expression shall be the type of the conditional_expression.
-Redundant[The expected type for each condition is expected to be of any
-boolean type (see 5.3).]
+If a conditional_expression is expected to be of a type T, the expected type for
+each dependent_expression of a conditional_expression is T. If a
+conditional_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
 
-If there is no "else" dependent_expression, the type of the conditional_expression
-shall be of a boolean type.
+If the expected type of a conditional_expression is any type in a class of types
+(instead of a particular type), all dependent_expressions of the
+conditional_expression shall have the same type.
+
+If there is no "else" dependent_expression, all of the dependent_expressions of
+the conditional_expression shall be of a boolean type.
+
+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,
+and is statically tagged otherwise.
 
+[Editor's note: We don't try to define the type of the conditional expression;
+it gets complex when implicit conversions are involved.]
+
     Dynamic Semantics
 
 For the execution of a conditional expression, the condition specified after
@@ -133,26 +183,17 @@
 [Editor's note: This is nearly a copy of 5.3(5). I left the clunkyness
 intact. Note that the last otherwise can be true only for a boolean
 conditional expression, as an "else" is required in all other cases.]
-
 
-In 4.7(2), add conditional_expression:
+Replace 4.7(2) by:
 
 qualified_expression ::=
-   subtype_mark'(expression) | subtype_mark'aggregate |
-   subtype_mark'conditional_expression
+   subtype_mark'(expression_within_parens) | subtype_mark'aggregate
 
 In 4.7(3), modify the start of the paragraph:
 
-The *operand* (the expression{,}[ or] aggregate{, or conditional_expression})
+The *operand* (the {expression_within_parens}[expression], or aggregate)
 shall...
 
-In 4.7(5), modify the note:
-
-When a given context does not uniquely identify an expected type, a
-qualified_expression can be used to do so. In particular, if an overloaded
-name{,}[ or] aggregate{, or conditional_expression} is passed to an overloaded
-subprogram, it might be necessary to qualify the operand to resolve its type.
-
 Add after 4.9(12):
 
 * A conditional_expression all of whose conditions and dependent_expressions are
@@ -199,24 +240,18 @@
 
 I don't think this level of detail is common enough to add to the language, but
 the introduction of the "statically unevaluated" term would make it easy to add
-here if desired.]
+this here if desired.]
 
 Delete 5.3(3-4) [they were moved to 4.5.7]
+
+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_expression all of whose dependent_expressions are permitted by this
+rule}:
 
-** TBD: We need wording to deal with built-in-place issues. In particular, a
-conditional expression ought to work like a set of parens rather than an aggregate
-with one component: no temporary object would be created (even logically). Some
-wording will be needed for this.
-
-** TBD: We also need to deal with the case that the various results have mixed
-tagged states: if one result is statically tagged and another is dynamically tagged,
-and the whole is used as the argument of a non-dispatching call, probably we need
-something to be illegal (we wouldn't want this to be a way to avoid 3.9.2(8-9)).
-[Well, I might, but that's a different issue. ;-)]
-
-** TBD: The name resolution rule needs to be replaced by one Tucker proposed (the
-last one preferably). That's in mail that hasn't been filed yet.
-** end TBD.
 
 
 !discussion
@@ -227,9 +262,16 @@
 
    if if Func1 then Func2 then Proc1; end if;
 
+   A := if B then C else D + 1;
+
 Even if the compiler can figure it out (which is not clear to the author), it
 would be dicey for a human, and small errors such as leaving out a semicolon
-could change the meaning of a statement drastically.
+could change the meaning of a statement drastically. In the second case, whether
+   A := (if B then C else D) + 1;
+or
+   A := (if B then C else D + 1);
+was meant will not be evident to the reader. Nor will the one selected by the
+compiler (the first one) be obvious.
 
 The obvious choice is to surround a conditional expression with parentheses.
 This is already a common Ada design choice, and will be familar to Ada
@@ -237,16 +279,37 @@
 Ada), or using syntax other than "if", would be less familar and would cause
 programmers a confusion as to which syntax to use in a given location.
 
-Thus, we design conditional expressions to work like and look like aggregates.
+Thus, we design conditional expressions to work like a fancy set of parentheses.
 This is the reason that they are defined to be a primary rather than some other sort
 of expression. The fact that the parentheses are required makes this preferable (it
 would be confusing otherwise).
+
+Requiring extra pairs of parentheses for conditional expressions is annoying.
+Consider:
+    pragma Assert ((if A then B else C));
+    Proc ((if A then B else C));
 
-One could imagine rules allowing the parentheses being omitted in contexts where
-they are not needed, such as a pragma argument. However, this would add
-conceptual overhead - it important to note that this was not done for aggregates
-except in the case of qualified expressions. It also would make syntax error
-correction much harder. Consider the following syntactically incorrect Ada code:
+We thus adopt rules to allow elimination of the extra parentheses in all contexts
+where they are directly nested and thus two sets of parantheses are directly adjacent.
+    pragma Assert (if A then B else C);
+    Proc (if A then B else C);
+
+(Note that we can't do this for aggregates, as the named notation of aggregates
+could also be the named notation of a call.)
+
+But we don't allow removing the parentheses in
+any other context, such as additional parameters, choices, etc.
+In particular, the extra parens are required for named notation:
+   Proc (Param => if A then B else C); -- Illegal.
+
+We considered additional cases where making parentheses optional would help.
+We wanted to allow the above case, but it becomes ambiguous for case expressions
+(AI05-188-1), and we want to use the same rules for all kinds of expressions.
+
+More aggresive rules would make it much harder to create unambiguous syntax rules.
+Most likely, the parentheses requirements would have to be enforced as legality
+rules. That would have the effect of making syntax error correction much harder.
+Consider the following syntactically incorrect Ada code:
 
      exit when if Foo then B := 10; end if;
 
@@ -257,34 +320,49 @@
 earlier. Nor would it be easy for the programmer to see where the error is.
 (Remember that Foo and B can be arbitrarily complex and on multiple lines.) With
 a required parenthesis, syntax correction would either identify the required
-parenthesis or the expression as missing, showing the correct point of the error.
+parenthesis or the expression as missing, showing the correct point of the
+error.
+
+[Editor's note: I tried the syntax changes recommended by Steve (explained in
+the Implementation Note in 4.4) in the grammar generator used by Janus/Ada, and
+they appeared to work without ambiguity. I didn't test the overall effect on
+error correction, but at least the rules can be enforced syntactically. That's
+important, because examples like the above will get an error at the "if", not
+some later point.]
+
+---
+
+Resolution of a conditional_expression also follows the model of parentheses.
+(That's made harder by the complete absence of such rules in the Ada Standard,
+so there is nothing to copy.)
+That is, whatever the context expects/requires is what is expected/required of
+the dependent expressions.
 
+We considered aggregate-like resolution, but that would have used too little of
+the context. For instance:
 
-Following the model of aggregates also simplifies the resolution of conditional
-expressions. This avoids nasty cases of resolution, in which a compiler might be
-able to figure out a unique meaning but a human could not. For instance, given
-the declarations:
+    Put_Line (Integer'Image (Num_Errors) &
+          (if Num_Errors = 1 then "error detected." else "errors detected."));
 
-   procedure Q (A, B : Integer);
-   procedure Q (A, B : Float);
+would be ambiguous because the operand of & could be either String or Character.
 
-   function F return Integer;
-   function F return Boolean;
+We augment the resolution rule with legality rules to ensure that all of the
+dependent_expressions have the same type if the context does not identify a
+particular type. This is needed to prevent cases like:
 
-   function G (N : Natural) return Integer;
-   function G (N : Natural) return Float;
+    type Some_Boolean is new Boolean;
+    function Foo return Some_Boolean;
 
-   Q ((if X > 3 then F else G(1)), (if X > 12 then G(2) else G(3)));
+    Cond : Boolean := ...;
+    Var  : Natural := ...;
 
-If we used full resolution, this would resolve to Integer because there is no F
-for Float. With the unlimited number of terms available in a conditional
-expression, one can construct ever more complex examples.
+    if (if Cond then Var > 10 else Foo) then ... -- Illegal by legality rule.
 
-Should we eventually find this to be too restrictive, changing to a full resolution
-model would be compatible (it would only make illegal programs legal), whereas
-going in other direction is would be incompatible. So it is best to start with
-the more restrictive rule.
+We also have a rule to disallow mixing statically tagged and dynamically
+tagged expressions in the same conditional_expression; that makes enforcing
+3.9.2(8) possible.
 
+---
 
 We allow the "else" branch to be omitted for boolean-valued conditional
 expressions. This eases the use of conditional expressions in preconditions
@@ -295,6 +373,7 @@
     pragma Assert(if A then B)
 In this case, the "else" branch is more noise than information.
 
+---
 
 Conditional_Expressions are static if all of their conditions and expressions
 are static. But expressions that are not used are not evaluated (and thus the
@@ -318,8 +397,8 @@
 
 ---
 
-There is no obvious term for the concept defined as "statically unevaluated" above.
-Here are some of the many choices considered:
+There is no obvious term for the concept defined as "statically unevaluated"
+above. Here are some of the many choices considered:
     statically unselected
     statically unevaluated
     statically unevaluable
@@ -330,9 +409,20 @@
     statically moot
     moot
 
-Each reviewer had a favorite, the author chose his but there is nothing resembling
-a consensus.
+Each reviewer had a favorite, the author chose his but there is nothing
+resembling a consensus.
 
+----
+
+We allow conditional_expressions in build-in-place contexts subject the normal
+rules for operands. The model is that a conditional_expression works like a
+set of parentheses; it does not copy any objects or create any temporaries on its
+own.
+
+The implementation of such a build-in-place conditional expression shouldn't be
+too complex; the address of the target object is passed to whichever
+dependent_expression is actually evaluated.
+
 !examples
 
 Another usage is fixing plurals in output. Much Ada code doesn't even try to
@@ -4933,3 +5023,2408 @@
 
 ****************************************************************
 
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  5:46 AM
+
+A thought, in light of the discussion of leaving out parens
+
+How about considering putting in the end if, and then not bothering with parens
+at all
+
+   A := if x then 2 else 3 end if;
+
+seems to read fine to me. I know I worried about error recovering in having END
+in the middle of expressions, but I think this is manageable ...
+
+By the way, I looked at how we do resolution in GNAT now for conditional
+expressions, and it is quite straightforward, we do the resolution of the type
+of the expression based on the THEN expression, and then force the ELSE
+expression to resolve to the same type .. quite straightforward.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Tuesday, March 23, 2009  6:06 AM
+
+...
+>   A := if x then 2 else 3 end if;
+>
+> seems to read fine to me.
+
+What worries me is when it appears in more complex expressions:
+
+A := if x then 2 else 3 end if + if y then 5 else 4 end if;
+
+You would certainly write it with parentheses in that case, so we end up with
+"end if" /and/ parentheses....
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  6:34 AM
+
+I don't see why you would write parens here, the IF/END IF to me act already as
+strong parens.
+
+I certainly never wrote (if x then y else z fi) in Algol-68, though in simple
+cases one would often use the short form in A-68 (x | y | z).
+
+****************************************************************
+
+From: John Barnes
+Sent: Tuesday, March 23, 2009  10:27 AM
+
+I would certainly prefer "end if" always;  And parens as well when it does not
+stand alone as a RHS or parameter or subscript perhaps.
+
+I used conditional expressions a lot in Algol60 and we had them in RTL/2 with
+the "end". And did not cloak then in parens.
+
+I hated their absence from Ada but with age I got used to it
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  11:52 AM
+
+A concern with omitting parens,
+
+if we allow parens to be omitted on a function call, but not on indexing or a
+type conversion, that's odd to me syntactically, and worse, it means that we
+have to deal with this during semantic analysis rather than parsing UGH!
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  11:51 AM
+
+> I would certainly prefer "end if" always;  And parens as well when it
+> does not stand alone as a RHS or parameter or subscript perhaps.
+
+OK, well count me as definitely opposed to requiring BOTH if/endif and parens at
+the same time, my suggestion was a possible way to get rid of the parens, not a
+way to add more stuff :-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  11:55 AM
+
+I implemented conditional expressions in GNAT (very easy, since we already had
+them, all we lacked was syntax :-)
+
+Here is a little test program:
+
+> with Text_IO; use Text_IO;
+> procedure t is
+> begin
+>    for J in 1 .. 3 loop
+>       Put_Line ((if J = 1 then "one"
+>                  elsif J = 2 then "two"
+>                  else "three"));
+>    end loop;
+>
+>    for J in Boolean loop
+>       if (if J then False else True) then
+>          Put_Line ("One");
+>       else
+>          Put_Line ("Two");
+>       end if;
+>    end loop;
+>
+>    for J in Boolean loop
+>       if (if J then False) then
+>          Put_Line ("One");
+>       else
+>          Put_Line ("Two");
+>       end if;
+>    end loop;
+> end t;
+
+
+and it's output:
+
+one
+two
+three
+One
+Two
+One
+Two
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, March 23, 2009  1:08 PM
+
+Cool.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  1:22 PM
+
+Just so no one gets alarmed, this construct will be rejected unless you use the
+special -gnatX (extensions allowed) switch on the compilation :-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  1:22 PM
+
+By the way Tuck, what do you think of the resolution rule we are using, seems
+very simple to understand and implement, and avoids the inflexibility of
+treating things as aggregates.
+
+I think I stated the rule on the ARG list, but if not, here it is:
+
+A conditional expression (if X then Y else Z) is resolved using the type of Y,
+just as though it had appeared simply as Y, then in the final resolution phase,
+Z is resolved using this same type, which must of course be unique. If Z cannot
+be resolved using this type, we have an error.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, March 23, 2009  1:49 PM
+
+That certainly seems simplest to implement, but I'll admit being a little
+uncomfortable about how asymmetric it is at a formal level.
+
+****************************************************************
+
+From: Steve Baird
+Sent: Tuesday, March 23, 2009  1:46 PM
+
+I would hope that the following example would not be rejected as being
+ambiguous:
+
+     type T1 is access This;
+     X1 : T1;
+
+     type T2 is access That;
+     X2 : T2;
+
+     Flag : Boolean := ... ;
+
+     procedure Foo (X : T1) is ... ;
+     procedure Foo (X : T2) is ... ;
+   begin
+     Foo ((if Flag then null else X1));
+
+How does the rule you describe handle this example?
+
+****************************************************************
+
+From: Edmond Schonberg
+Sent: Tuesday, March 23, 2009  2:05 PM
+
+> I think I stated the rule on the ARG list, but if not, here it is:
+>
+> A conditional expression (if X then Y else Z) is resolved using the
+> type of Y, just as though it had appeared simply as Y, then in the
+> final resolution phase, Z is resolved using this same type, which must
+> of course be unique. If Z cannot be resolved using this type, we have
+> an error.
+
+You need to deal with the case where Y and/or Z are both overloaded calls. It is
+here that intersection of types is needed (no big deal)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, March 23, 2009  2:58 PM
+
+> What worries me is when it appears in more complex expressions:
+>
+> A := if x then 2 else 3 end if + if y then 5 else 4 end if;
+>
+> You would certainly write it with parentheses in that case, so we end
+> up with "end if" /and/ parentheses....
+
+I agree with Jean-Pierre. This syntax would be impossible to read in some
+circumstances. As Adam suggested today on Ada-Comment:
+
+if if if x then y end if then False end if then ...
+
+Even the possibility of this makes me think I have the flu again...
+
+Besides, I've already found that in writing a conditional expression, I
+naturally put in semicolons and have to remove them. My point is that this
+syntax is never going to be exactly the same as an if statement, so I don't see
+any advantage to the "end if".
+
+Robert made the claim that error correction is "manageable". That might be true
+for some forms of parser, but I'm pretty sure that there is no hope for our
+purely table-driven parser. We'd pretty much have to give up if you left out
+something in the above expression. I don't think there would be any sane way to
+tell between an if statement and a conditional expression in the above syntax,
+but they go very different places. So I would be strongly opposed to leaving out
+the parens in conditions (if statements, when parts of exits, etc.) -- anywhere
+where a simple omission could allow an if statement to be legal.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  6:54 PM
+
+> That certainly seems simplest to implement, but I'll admit being a
+> little uncomfortable about how asymmetric it is at a formal level.
+
+Yes, but you really get into a mess if you try to make it symmetrical I fear.
+Unless you say .. try both and if one works OK, you run the risk of making
+things more restrictive than this asymmetrical definition/implementation.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  6:58 PM
+
+...
+> How does the rule you describe handle this example?
+
+It would be ambiguous, but so would
+
+    Foo (null)
+
+so what's the big deal?
+
+I don't mind figuring out a rule that allows this case provided that
+
+a) it is easy to implement
+
+b) it is no more restrictive than the rule I proposed.
+
+What I do object to is the aggregate/simple type rule which would make the
+posted example with strings ambiguous.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, March 23, 2009  7:04 PM
+
+> You need to deal with the case where Y and/or Z are both overloaded
+> calls. It is here that intersection of types is needed (no big deal)
+
+well I would say "you may want to deal", we don't currently and I am not sure it
+is worth complexifying things for this. But certainly that would be acceptable
+to me. And is symmetrical.
+
+My view is that
+
+(if A then B then C)
+
+must work in a context where
+
+B
+
+or
+
+C
+
+on their own would work and yield the same type, I don't mind if we allow more
+cases, but we should allow at least this much. My rule allows more since it
+would allow Steve's example with null in the else part.
+
+I do see the discomfort with asymmetricality
+
+   (if A then B else C)       OK
+   (if not A then C else B)   KO
+
+is odd, but will it really happen in practice?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, March 23, 2009  8:11 PM
+
+> You need to deal with the case where Y and/or Z are both overloaded
+> calls. It is here that intersection of types is needed (no big deal)
+
+I agree it's not that big of a deal to implement.
+And for uniformity with other resolution rules, I'd make it symmetric (so
+Steve's example resolves).
+
+But note that it's not just "both overloaded" -- it's "all overloaded", because
+you can have a chain of elsif's, and you have to intersect the possible types of
+all of them, as well as the type(s) determined from context.  I thought this was
+the rule Robert was advocating all along.  It matches the "simple" Algol 68 rule
+(at least, my understanding of the Algol 68 rule based on a phone conversation
+with Robert last week).
+
+Note that the GNAT implementation turns elsif chains into nested if-then-else's.
+
+And note that I'm now convinced that the "resolve like an aggregate"
+rule is too restrictive.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, March 23, 2009  8:27 PM
+
+...
+> And note that I'm now convinced that the "resolve like an aggregate"
+> rule is too restrictive.
+
+For the record, so am I.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Tuesday, March 23, 2009  8:01 PM
+
+...
+> > But I just realized that the "single type" rule Randy and I have
+> > been advocating also makes this ambiguous!  Uh oh.
+>
+> OK, is that enough to convince you, ...
+
+Yes (given that it's too late to get rid of the annoying component-wise "&"
+operators).
+
+>...or will you suddenly decide that
+> it makes things more readinable to write
+>
+> >>     Put_Line (Integer'Image (Num_Errors) &
+> >>           String'(if Num_Errors = 1 then "error detected." else
+> >> "errors detected."));
+>
+> :-)
+
+No, I won't decide that this is more readable!  ;-)
+
+****************************************************************
+
+From: Steve Baird
+Sent: Tuesday, March 23, 2009  9:04 PM
+
+...
+> What I meant is the standard two-pass resolution algorithm that no
+> doubt we all use!  We identify candidate interpretations bottom-up,
+> and we find the single interpretation for a complete context top-down.
+> I'm not proposing anything different: find interpretations of each
+> expression, find the common intersection, and these are the candidate
+> interpretations of the conditional expression as a whole.  The full
+> context will then indicate the expected type for it, and that gets
+> propagated to each expression (which may have be overloaded).
+>
+
+...
+> I do see the discomfort with asymmetricality
+>
+>   (if A then B else C)       OK
+>   (if not A then C else B)   KO
+>
+> is odd, but will it really happen in practice?
+
+I think that Ed has outlined the "right" solution, based on the principle of
+least surprise.
+
+Perhaps the cases where this more general rule is required won't come up very
+often in practice, but they will be annoying and/or mystifying when they do (if
+these cases are disallowed). Users could certainly live with such rules, but why
+would we want to ask them to?
+
+I think Ed has already noted that the intersection operator has to deal with
+cases where one of the operands is something like "the set of all access types"
+or "the set of all composite types". but this doesn't seem like a big deal.
+
+Just my opinion.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, March 23, 2009  9:43 PM
+
+...
+> Perhaps the cases where this more general rule is required won't come
+> up very often in practice, but they will be annoying and/or mystifying
+> when they do (if these cases are disallowed). Users could certainly
+> live with such rules, but why would we want to ask them to?
+>
+> I think Ed has already noted that the intersection operator has to
+> deal with cases where one of the operands is something like "the set
+> of all access types" or "the set of all composite types". but this
+> doesn't seem like a big deal.
+
+What "intersection operator"? I think you are assuming a lot if you think that
+there is some general purpose "intersection" operators in most compilers. Surely
+Janus/Ada doesn't have one.
+
+For calls, we try to solve each parameter to the parameter type for every
+possible interpretation. (We once tried to save intermediate results for such
+attempts, but it turned out that in practice multiple occurrences of a single
+type is rare, and the overhead to save the results was actually much worse than
+the time saved.) If there's more than one that works at any point, then the
+expression is ambiguous and we give up. (Note that there may be more than one
+*of different types* that is live at some point, but not of the same type).
+
+There is a special case hack to deal with solving pairs of expressions at once,
+such as the bounds of a range or the two sides of an assignment. There is one
+for memberships as well (that is three possibilities): it takes 500 lines of
+code! I don't know of any way to generalize this code (if we knew of a way, we
+would have done it in the first place).
+
+While I'm sure that this can be resolved (and I didn't write this code, so it's
+possible that there is something that I've missed), I don't think it would be as
+easy as Ed suggests. Whereas, the aggregate resolution would be easy to apply.
+
+That said, I understand the problem with aggregate resolution, so it may be
+appropriate to go with the more complex resolution. Just don't make claims like
+"it is easy to do", because I don't see any reason to assume that.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 24, 2009  4:57 AM
+
+This is the Name Resolution wording I suggested in an earlier reply.  I think it
+is about right:
+
+    The expected type for each dependent expression is that of
+    the conditional expression as a whole.  All dependent expressions
+    shall resolve to the same type.  The type of the conditional
+    expression as a whole is this same type.  If there is no ELSE part,
+    this type shall be a boolean type.
+
+  This approach will ensure that the expected type has to be a suitable
+  "single" type if any one of the dependent expressions requires a single
+  type.  For example, if one of the dependent expressions is a string
+  literal, then the expected type has to be a single string type.
+  We certainly don't want to have to start searching for all in-scope
+  string types to resolve a conditional expression.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, March 24, 2009  5:32 AM
+
+Seems a pity that this rule is more complicated to implement than the current
+asymmetric rule applied by GNAT *and* more restrictive. So we have a rule whose
+only merit is that it is more aesthetic to describe, hmmmmmm ...
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 24, 2009  5:47 AM
+
+Can you give an example where it is
+more restrictive?  It isn't intended
+to be.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, March 24, 2009  7:01 AM
+
+Maybe I don't understand your suggestion, suppose we have two procedures
+
+   type S1 is new String;
+   type S2 is new String;
+
+   procedure P (A : S1);
+   procedure P (A : S2);
+
+   V1 : S1 := ...
+
+   P ((if B then V1 else "xyz"));
+
+The rule I suggested (and of course the intersection rule) would resolve this,
+but as I understand your suggestion, it would not resolve since "xyz" does not
+have a unique type considered on its own.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Wednesday, March 24, 2009  8:59 AM
+
+But would you resolve:
+   P ((if B then "xyz" else V1));
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, March 24, 2009  8:34 AM
+
+Tucker, please explain how your proposed rule deals with Robert's example, and
+also with this:
+
+    P((if A then "xxx" elsif B then "yyy" elsif C then "zzz" else V1));
+
+presuming A, B, and C are not overloaded -- just Boolean variables, say.
+
+Also, how does it deal with my earlier example:
+
+    Put_Line (Integer'Image (Num_Errors) &
+              (if Num_Errors = 1 then "error" else "errors") &
+              "detected.");
+
+assuming there is just one visible Put_Line that takes String, and the usual "&"
+ops are visible?
+
+Also, what if there are two Put_Lines, one for String, and one for
+Wide_Wide_String?
+
+I think Ed and Steve are saying all of the above should resolve, and I think I
+agree.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 24, 2009  9:20 AM
+
+> P ((if B then V1 else "xyz"));
+
+No, the rule as suggested would resolve this.
+When some rule says that the expected type must be a "single type" that doesn't
+mean that there can only be one overloading, but rather it means that the
+expected type is not something like "any composite" or "any string". In
+particular, it can't be the operand of a type conversion.  See 8.6(27/2) for the
+formalities.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, March 24, 2009  8:55 AM
+
+> I think that Ed has outlined the "right" solution, based on the
+> principle of least surprise.
+>
+> Perhaps the cases where this more general rule is required won't come
+> up very often in practice, but they will be annoying and/or mystifying
+> when they do (if these cases are disallowed). Users could certainly
+> live with such rules, but why would we want to ask them to?
+
+Shrug.  I think you overestimate the knowledge of typical Ada programmers. The
+way people program is sloppy with regard to overloading:  Declare whatever names
+make sense, without thinking much about overloading.  Write down references to
+possibly-overloaded stuff willy-nilly.  If it resolves, fine. If it's ambiguous,
+stick in qualified expressions.  If there end up being too many qualified
+expressions, change some of the subp names to be less overloaded.
+
+There's nothing wrong with this sloppiness -- programmers shouldn't have to
+understand the overloading rules.  They just need a vague understanding:
+Overloading is allowed, and the compiler figures things out based on types, and
+you can use qualification to resolve ambiguities.
+
+In fact, even I (who do understand the overloading rules, when I've got my
+language lawyer hat on) program in this sloppy way -- I'm not thinking much
+about the exact rules when I program.
+
+Nonentheless, I think I agree with your conclusion.  It seems like the simplest
+rule (even if not the simplest to implement), and it's uniform with things like
+":=".
+
+> I think Ed has already noted that the intersection operator has to
+> deal with cases where one of the operands is something like "the set
+> of all access types" or "the set of all composite types".
+> but this doesn't seem like a big deal.
+
+Agreed.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, March 24, 2009  2:19 PM
+
+Here is the proposed rule yet again:
+
+    The expected type for each dependent expression is that of
+    the conditional expression as a whole.  All dependent expressions
+    shall resolve to the same type.  The type of the conditional
+    expression as a whole is this same type.  If there is no ELSE part,
+    this type shall be a boolean type.
+
+For Robert's example:
+
+ >>    type S1 is new String;
+ >>    type S2 is new String;
+ >>
+ >>    procedure P (A : S1);
+ >>    procedure P (A : S2);
+ >>
+ >>    V1 : S1 := ...
+ >>
+ >>    P ((if B then V1 else "xyz"));
+
+Both P's would be considered. When considering the first P, the expected type
+for "V1" and "xyz" would be S1.  For the second P, the expected type would be S2
+for each. Clearly only the first P would be an "acceptable" interpretation. So
+this would be unambiguous.
+
+For this example:
+
+      P((if A then "xxx" elsif B then "yyy" elsif C then "zzz" else V1));
+
+the expected type for each of the dependent expressions would be the type of the
+first formal parameter of P.  If there are multiple P's, then those are each
+considered in turn to find if any of them are "acceptable" interpretations.
+Presumably only the P's whose parameter is of a string type and that also
+matches "V1" would be acceptable.   If there is exactly one such "P" then all is
+well. If more than one, it is ambiguous.  If none, then no dice.
+
+This would be roughly equivalent to taking each P and giving it four parameters
+all of the same type.  If that resolves, then so would this.
+
+For this example:
+
+ >
+ >     Put_Line (Integer'Image (Num_Errors) &
+ >               (if Num_Errors = 1 then "error" else "errors") &
+ >               "detected.");
+ >
+ > assuming there is just one visible Put_Line that takes String,
+ > and the usual "&" ops are visible?
+
+Then all directly visible overloadings of "&" with result type String would be
+considered.  Only those that have a single string type as their parameter type
+would end up acceptable.  If there is more than one, then it is ambiguous.
+Clearly there is at least one, since the "&"(String,String)=>String in package
+Standard will do the job.
+
+For this one:
+
+ > Also, what if there are two Put_Lines, one for String, and one for
+ > Wide_Wide_String?
+
+Both Put_Line's would be considered, but only the one with formal parameter of
+type String would be acceptable, the only "&" that matches Integer'Image with
+its Left operand is the one for String.
+
+This is all pretty standard overloading stuff.
+All the rule I have suggested said is that the expected type is passed down to
+all of the dependent expressions, with the additional requirement that all of
+them end up resolving to the same type.  The additional requirement is generally
+redundant, unless the "expected type" turns out to be something very general
+like "any nonlimited type" or equivalent.
+
+Reading name resolution rules is never easy, but the one I suggested isn't that
+much different from many others in the language.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, March 24, 2009  2:53 PM
+
+> This is all pretty standard overloading stuff.
+
+Yes, pretty standard.  Not sure why I was confused earlier.
+
+So your wording is equivalent to Ed's and Steve's notion of intersecting sets of
+types, which is a more mechanistic way of looking at it.
+
+Thanks for clarifying.  For the record, I am happy with your proposed rule.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, March 24, 2009  6:45 PM
+
+OK I understand Tuck's rule, and it seems fine (seems equivalent to Ed's
+intersection description actually :-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Saturday, March 28, 2009  7:04 AM
+
+> What "intersection operator"? I think you are assuming a lot if you
+> think that there is some general purpose "intersection" operators in
+> most compilers. Surely Janus/Ada doesn't have one.
+>
+> For calls, we try to solve each parameter to the parameter type for
+> every possible interpretation. (We once tried to save intermediate
+> results for such attempts, but it turned out that in practice multiple
+> occurrences of a single type is rare, and the overhead to save the
+> results was actually much worse than the time saved.) If there's more
+> than one that works at any point, then the expression is ambiguous and
+> we give up. (Note that there may be more than one *of different types*
+> that is live at some point, but not of the same type).
+>
+> There is a special case hack to deal with solving pairs of expressions
+> at once, such as the bounds of a range or the two sides of an
+> assignment. There is one for memberships as well (that is three
+> possibilities): it takes 500 lines of code! I don't know of any way to
+> generalize this code (if we knew of a way, we would have done it in the first
+> place).
+
+Randy, it seems like you have handled resolution with a series of special case
+hacks instead of a general scheme. There is nothing inherently wrong with that
+approach if it works, but it is not surprising that you have to keep adding more
+special case hacks when more features are added to the language. Perhaps at some
+point you might want to consider getting rid of these hacks and using a more
+general resolution scheme (you can always look at the GNAT code for an example
+:-)
+
+But anyway, in this situation, I don't see this is an argument against what
+seems to be the most reasonable resolution rule from a language point of view.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 30, 2009  2:21 PM
+
+> Randy, it seems like you have handled resolution with a series of
+> special case hacks instead of a general scheme.
+> There is nothing inherently wrong with that approach if it works, but
+> it is not surprising that you have to keep adding more special case
+> hacks when more features are added to the language. Perhaps at some
+> point you might want to consider getting rid of these hacks and using
+> a more general resolution scheme (you can always look at the GNAT code
+> for an example :-)
+
+I'm pretty sure I have better things to do than to replace working code,
+especially for something as complex as resolution. Especially without any
+customer demand for such a change.
+
+But upon reflection, I think that membership probably is the wrong example. In a
+membership, there is no information from the context as to the type that you
+need to resolve to. That's what makes it so messy in our algorithm. A
+conditional expression does not have that problem, so it in fact may not be a
+problem to do full resolution on it.
+
+> But anyway, in this situation, I don't see this is an argument against
+> what seems to be the most reasonable resolution rule from a language
+> point of view.
+
+That's true. Nor is the claim that it is easy in some implementation much of an
+argument for a resolution rule. In general, arguments (either for or against)
+based on a single implementation are very weak.
+
+In this case, I would have preferred a less complex resolution rule, for all of
+the reasons I outlined in the AI. But I've seen enough examples where it
+wouldn't work very well to realize that the more complex rule is probably
+necessary in this case.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 30, 2009  3:02 PM
+
+We have implemented this resolution rule for conditional expressions, and for us
+it was a fairly simple fix (less than 10 lines fix).
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, March 30, 2009  3:38 PM
+
+Can you elaborate slightly when you say "this" resolution rule.
+Is this a symmetric one, which takes context into account?
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 30, 2009  5:49 PM
+
+yes
+
+****************************************************************
+
+From: Edmond Schonberg
+Sent: Monday, March 30, 2009  4:10 PM
+
+Yes: the expressions may be overloaded, and are resolved from context.  This is
+not different from operator resolution: the candidate interpretations of the
+conditional  expression are the types common to the types of the constituent
+expressions that follow "then"  and "else",  The context eventually selects one
+of those types, which is used to complete the resolution of each expression.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, March 30, 2009  4:40 PM
+
+Would you say this is an implementation of the rule for which I proposed
+wording, or is it implementing some other wording?  Here is the wording I
+proposed:
+
+    The expected type for each dependent expression is that of
+    the conditional expression as a whole.  All dependent expressions
+    shall resolve to the same type.  The type of the conditional
+    expression as a whole is this same type.  If there is no ELSE part,
+    this type shall be a boolean type.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 30, 2009  6:07 PM
+
+I think it is the same, though I must say, I find the above wording difficult to
+understand precisely.
+
+What we implement exactly is to gather the set of possible types for each
+operand, given the context, then do an intersection between these two sets, and
+there must be exactly one type in the intersection.
+
+It's actually exactly the same as A + B really ...
+
+****************************************************************
+
+From: Edmond Schonberg
+Sent: Monday, March 30, 2009  7:09 PM
+
+> Would you say this is an implementation of the rule for which I
+> proposed wording, or is it implementing some other wording?  Here is
+> the wording I proposed:
+>
+>   The expected type for each dependent expression is that of
+>   the conditional expression as a whole.  All dependent expressions
+>   shall resolve to the same type.  The type of the conditional
+>   expression as a whole is this same type.  If there is no ELSE part,
+>   this type shall be a boolean type.
+
+Yes, our implementation is equivalent to the above.  The description you give is
+global, while the description I gave of our implementation is operational, and
+reflects the standard two-pass algorithm.  Just to make sure, here is the
+program we are using as a simple test case:
+
+with Text_IO; use Text_IO;
+procedure Condifo is
+    type I1 is new Integer;
+    type I2 is new Integer;
+    type I3 is new Integer;
+    V1 : I1;
+    V2 : I2;
+    V3 : I3;
+
+    procedure P (Arg : I1) is
+    begin
+       Put_Line ("P/I1 called");
+    end P;
+
+    procedure P (Arg : I2) is
+    begin
+       Put_Line ("P/I2 called");
+    end P;
+
+    procedure P2 (Arg1 : I1; Arg3 : I3) is
+    begin
+       Put_Line ("P/I1-I3 called");
+    end P2;
+
+    procedure P2 (Arg1 : I1; Arg2 : I1) is
+    begin
+       Put_Line ("P/I1-I2 called");
+    end P2;
+
+    function F return I1 is
+    begin
+       Put_Line ("F/I1 called");
+       return 1;
+    end F;
+
+    function F return I2 is
+    begin
+       Put_Line ("F/I2 called");
+       return 2;
+    end F;
+
+    function Q return I1 is
+    begin
+       Put_Line ("Q/I1 called");
+       return 1;
+    end Q;
+
+    function Q return I2 is
+    begin
+       Put_Line ("Q/I2 called");
+       return 2;
+    end Q;
+
+    function R return I3 is
+    begin
+       Put_Line ("R/I3 called");
+       return 3;
+    end R;
+
+    function R return I2 is
+    begin
+       Put_Line ("R/I2 called");
+       return 2;
+    end R;
+
+begin
+    for J in Boolean loop
+       P (if J then V1 else F);
+    end loop;
+
+    New_Line;
+
+    for J in Boolean loop
+       P (if J then F else V2);
+    end loop;
+
+    New_Line;
+
+    for J in Boolean loop
+       P (if J then Q else R);
+    end loop;
+
+    for J in Boolean loop
+       P (if J then Q elsif (not J) then  R else F);
+    end loop;
+
+    for J in Boolean loop
+       P2 (if J then Q else F, R);
+    end loop;
+end Condifo;
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 30, 2009  7:34 PM
+
+> >     The expected type for each dependent expression is that of
+> >     the conditional expression as a whole.  All dependent expressions
+> >     shall resolve to the same type.  The type of the conditional
+> >     expression as a whole is this same type.  If there is no ELSE part,
+> >     this type shall be a boolean type.
+>
+> I think it is the same, though I must say, I find the above wording
+> difficult to understand precisely.
+
+I think the wording is either overly complex or wrong - it surely seems more
+confusing than necessary.
+
+> What we implement exactly is to gather the set of possible types for
+> each operand, given the context, then do an intersection between these
+> two sets, and there must be exactly one type in the intersection.
+>
+> It's actually exactly the same as A + B really ...
+
+Well, almost: a conditional expression can have any number of expressions while
+A+B only has two. But the principle is correct: the effect ought to be the same
+as
+    function Cond_Expr (Then_Part, {Elsif_Part_n,} Else_Part : T) return T;
+
+But Tucker's wording doesn't seem to have that effect. For one thing, it seems
+to disallow the "covered-by" rules. In:
+
+   function F (A : T; B : T'Class) return T'Class is
+   begin
+       return (if Something then A else B);  -- OK?
+       if Something then
+           return A; -- OK.
+       else
+           return B; -- OK.
+       end if;
+   end F;
+
+A and B resolve to different (but compatible) types. I'm basing this on the
+wording in 8.6(22-25.1/2) - there it says that if the expected type is a
+specific type T, then the construct shall resolve to T, or T'Class, etc.
+
+If we really wanted these all to be the same type (and ignore "covered by"
+and the like), we probably should write that as a legality rule after
+resolution. (We don't want to have resolution any more specific than necessary.)
+But I don't think that is what we want - if it was, I don't see why we would
+want to try so hard to make aggregates and string literals work without
+qualification.
+
+I think Tucker is trying to say that all of the expressions have to resolve when
+their expected type is the type that the entire conditional expression resolves
+to. But that's recursive and doesn't make much sense.
+
+(Interestingly, the "aggregate" rule would have worked fine on this example, as
+does the function analog rule. Just not the rule Tucker wrote.)
+
+I understand that the reason for the complexity here is to deal with the case
+where a conditional expression is used in a place that allows "any <something>
+type", such as an if statement (which allows "any boolean type"):
+
+    function ">" (Left, Right : T) return Some_Boolean;
+
+    if (if Something then A > B else True) then
+
+One would hope that this would work and resolve to Some_Boolean (with the "True"
+being of type Some_Boolean). But it is hard to get too excited about using
+conditional expressions in such contexts (if statements, case statements, type
+conversions). I suppose we have to ensure that we prevent something like:
+
+    function ">" (Left, Right : T) return Some_Boolean;
+    function "=" (Left, Right : T) return Boolean;
+
+    if (if Something then A > B else A = B) then
+
+We don't want the expressions to have different types. But a legality rule would
+be enough to prevent this case.
+
+Anyway, there must be a better way to word this. One that is correct would be
+nice! (Not that I can figure it out, unfortunately.)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, March 30, 2009  7:49 PM
+
+> Well, almost: a conditional expression can have any number of
+> expressions while A+B only has two. But the principle is correct: the
+> effect ought to be the same as
+>     function Cond_Expr (Then_Part, {Elsif_Part_n,} Else_Part : T)
+> return T;
+
+Actually elseif's are easy to handle, we just rewrite
+
+    (if a then b elsif c then d elsif e then f else g)
+
+as
+
+    (if a then b else (if c then d else (if e then f else g)))
+
+and we only have to worry about the two operand case
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, March 30, 2009  9:15 PM
+
+I'm happy to have someone else propose wording, but let me explain what I have
+proposed already:
+
+First, it is important to know what is the *expected type* of each dependent
+expression, because without that there are a whole lot of rules which don't
+work.  I presume we all agree it should be the same as that of the conditional
+expression as a whole.
+
+Secondly, we need to know what is the *type* of the conditional expression as a
+whole.  It seems clear that it wants to be the same as the type of each of the
+dependent expressions.  This latter requirement can also help resolve ambiguity,
+and corresponds to the "intersection" that has been mentioned several times.
+
+The last part about "boolean" seems pretty straightforward.
+
+So I don't see how it could be phrased much more simply, but I may be blind to
+some obvious easier approach.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 30, 2009  9:54 PM
+
+> First, it is important to know what is the *expected type* of each
+> dependent expression, because without that there are a whole lot of
+> rules which don't work.  I presume we all agree it should be the same
+> as that of the conditional expression as a whole.
+
+Right, no problem here.
+
+> Secondly, we need to know what is the *type* of the conditional
+> expression as a whole.  It seems clear that it wants to be the same as
+> the type of each of the dependent expressions.  This latter
+> requirement can also help resolve ambiguity, and corresponds to the
+> "intersection" that has been mentioned several times.
+
+But this I don't agree with (at least pedantically): it means that none of the
+classwide conversions will work. We go to great lengths to make an object of
+T'Class work (almost) everywhere that an object of T works, and the rule you are
+proposing here does not allow that.
+
+That's because the type of an expression is still T'Class even if the expected
+type is T (or vice versa). So the rule that you proposed is *WRONG* (not just
+confusing), at least if you expect the classwide rules to work as usual (I
+certainly do!). You can't talk about the type of a subexpression without adding
+an unnecessary restriction to the language, because it is perfectly reasonable
+for them to be different.
+
+Note that the rule you have also would deny the use of conditional expressions
+for anonymous access types, because they also use these "resolve to some other
+type" rules. The problem potentially would happen anywhere that Ada has an
+implicit conversion, because the language phrases these in terms of resolving to
+some type other than the expected type.
+
+Now, I agree with the basic principle that you are suggesting, the problem is
+that the way the language is worded you don't get the correct result.
+
+> The last part about "boolean" seems pretty straightforward.
+>
+> So I don't see how it could be phrased much more simply, but I may be
+> blind to some obvious easier approach.
+
+It's irrelevant whether it can be more simple, the question is whether it can be
+phrased *correctly*. Then we can go for simpler!
+
+The only rule that I can think of that would work at all is to phrase it in
+terms of an equivalence to a function call (as described previously):
+
+    function Cond_Expr (Then_Part, {Elsif_Part_n,} Else_Part : T) return T;
+
+This is what is implemented in GNAT if I understand correctly, not the rule that
+you described.
+
+But of course we have a natural aversion to "equivalences".
+
+The only way that some rule about same types would work would be if we required
+all of the expressions to have a single expected type (that is, the same
+expected type for all expressions, and no "any"s). But I think that is a new
+invention. We definitely cannot talk about the type that the expressions resolve
+to.
+
+We could also part about the types of the expressions being the same completely.
+(The expected types already define everything that we need to know). But that
+leads to other annoyances in the case of resolving to "any boolean type" and the
+like. So I don't think that is a good route.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, March 30, 2009  10:27 PM
+
+> But this I don't agree with (at least pedantically): it means that
+> none of the classwide conversions will work. We go to great lengths to
+> make an object of T'Class work (almost) everywhere that an object of T
+> works, and the rule you are proposing here does not allow that.
+
+I'm not sure I follow.  We still allow T'Class where T is expected.
+But I think we should require *all* of the dependent expressions to be
+class-wide, not just some of them, if you want dispatching to occur.
+
+> That's because the type of an expression is still T'Class even if the
+> expected type is T (or vice versa). So the rule that you proposed is
+> *WRONG* (not just confusing), at least if you expect the classwide
+> rules to work as usual (I certainly do!). You can't talk about the
+> type of a subexpression without adding an unnecessary restriction to
+> the language, because it is perfectly reasonable for them to be different.
+
+I don't think I fully understand you terminology.  What do you mean "you can't
+talk about the type of a subexpression"?
+
+But I think I am seeing your point.  Probably the best fix is to say that *if
+the expected type is not a single type* then all of the dependent expressions
+shall resolve to the same type.  On the other hand, if the expected type is a
+single type, then the only requirement might be a legality rule about
+dispatching.  It would be similar to the existing rule that requires all
+controlling operands to be dynamically tagged if any of them are.  This would
+carry down to the dependent expressions.  All or none are dynamically tagged. Or
+something like that.
+
+> Note that the rule you have also would deny the use of conditional
+> expressions for anonymous access types, because they also use these
+> "resolve to some other type" rules. The problem potentially would
+> happen anywhere that Ada has an implicit conversion, because the
+> language phrases these in terms of resolving to some type other than the expected type.
+
+Yes, I see your point, and I agree we don't need to require that all dependent
+expressions resolve to the same type if there is an expected type that is a
+single type.  If the expected type isn't a single type, then the "intersection"
+rule would apply.
+
+Here is a possible rewording of the Name Resolution part.  The legality rule
+about all-or-none being dynamically tagged is not covered here:
+
+     The expected type for each dependent expression is that of
+     the conditional expression as a whole.  If the expected type
+     is not a single type, then all dependent expressions
+     shall resolve to the same type, and the type of the conditional
+     expression as a whole is this same type.  If there is no ELSE part,
+     each dependent expression shall resolve to a boolean type.
+
+...
+> We could also part about the types of the expressions being the same
+> completely. (The expected types already define everything that we need
+> to know). But that leads to other annoyances in the case of resolving
+> to "any boolean type" and the like. So I don't think that is a good route.
+
+See above for another possible wording.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, March 30, 2009  11:35 PM
+
+...
+> But I think I am seeing your point.  Probably the best fix is to say
+> that *if the expected type is not a single type* then all of the
+> dependent expressions shall resolve to the same type.  On the other
+> hand, if the expected type is a single type, then the only requirement
+> might be a legality rule about dispatching.  It would be similar to
+> the existing rule that requires all controlling operands to be
+> dynamically tagged if any of them are.  This would carry down to the
+> dependent expressions.  All or none are dynamically tagged.
+> Or something like that.
+
+Ah yes, I forgot about that rule. (Not one of my favorite rules in the language.
+Aside: I recall telling Isaac that we needed to enforce that "stupid" rule, and
+he wrote a routine called "Check_Stupid_Tagged_Rule" to do so. It's still there
+in the Janus/Ada compiler. Apparently, I was a bit too opinionated when
+explaining it to him. :-)
+
+I would think that we would only want to enforce that where it mattered (as a
+parameter to a call); it would be weird to require type conversions in a return
+statement (for instance) that wouldn't have any problem if written as an if
+statement with two returns. (See my original mail on this topic for an example.
+
+...
+> Here is a possible rewording of the Name Resolution part.
+> The legality rule about all-or-none being dynamically tagged is not
+> covered here:
+>
+>      The expected type for each dependent expression is that of
+>      the conditional expression as a whole.  If the expected type
+>      is not a single type, then all dependent expressions
+>      shall resolve to the same type, and the type of the conditional
+>      expression as a whole is this same type.  If there is no ELSE part,
+>      each dependent expression shall resolve to a boolean type.
+
+Much better. The only glitch here is that we don't ever say what the type of the
+conditional expression is if the expected type is a single type. I guess that is
+typical (I don't see any wording about the type of an aggregate for instance),
+but it looks weird in this context. So perhaps add an Otherwise clause to avoid
+confusion:
+
+      The expected type for each dependent expression is that of
+      the conditional expression as a whole.  If the expected type
+      is not a single type, then all dependent expressions
+      shall resolve to the same type, and the type of the conditional
+      expression as a whole is this same type.  Otherwise, the type of
+      the conditional expression is the single expected type. If there
+      is no ELSE part, each dependent expression shall resolve to a boolean
+      type.
+
+Adding appropriate Redundant brackets.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, March 31, 2009  5:47 AM
+
+> ...
+>> But I think I am seeing your point.  Probably the best fix is to say
+>> that *if the expected type is not a single type* then all of the
+>> dependent expressions shall resolve to the same type.  On the other
+>> hand, if the expected type is a single type, then the only
+>> requirement might be a legality rule about dispatching.  It would be
+>> similar to the existing rule that requires all controlling operands
+>> to be dynamically tagged if any of them are.  This would carry down
+>> to the dependent expressions.  All or none are dynamically tagged.
+>> Or something like that.
+>
+> Ah yes, I forgot about that rule. (Not one of my favorite rules in the
+> language. Aside: I recall telling Isaac that we needed to enforce that
+> "stupid" rule, and he wrote a routine called
+> "Check_Stupid_Tagged_Rule" to do so. It's still there in the Janus/Ada
+> compiler. Apparently, I was a bit too opinionated when explaining it
+> to him. :-)
+>
+> I would think that we would only want to enforce that where it
+> mattered (as a parameter to a call); it would be weird to require type
+> conversions in a return statement (for instance) that wouldn't have
+> any if written as an if statement with two returns. (See my original
+> mail on this topic for an example.
+
+The only place where you can pass T'Class with an expected type of T is as part
+of a dispatching call, and in those contexts you aren't allowed to mix
+statically tagged and dynamically tagged operands, according to RM 3.9.2(8).
+
+On the other hand, if the expected type is T'Class, then there seems no reason
+to require that all the dependent expressions resolve to the same type covered
+by T'Class, nor that all or none be class-wide.
+
+>  ...
+>> Here is a possible rewording of the Name Resolution part.
+>> The legality rule about all-or-none being dynamically tagged is not
+>> covered here:
+>>
+>>      The expected type for each dependent expression is that of
+>>      the conditional expression as a whole.  If the expected type
+>>      is not a single type, then all dependent expressions
+>>      shall resolve to the same type, and the type of the conditional
+>>      expression as a whole is this same type.  If there is no ELSE part,
+>>      each dependent expression shall resolve to a boolean type.
+>
+> Much better. The only glitch here is that we don't ever say what the
+> type of the conditional expression is if the expected type is a single
+> type. I guess that is typical (I don't see any wording about the type
+> of an aggregate for instance), but it looks weird in this context. So
+> perhaps add an Otherwise clause to avoid confusion:
+>
+>       The expected type for each dependent expression is that of
+>       the conditional expression as a whole.  If the expected type
+>       is not a single type, then all dependent expressions
+>       shall resolve to the same type, and the type of the conditional
+>       expression as a whole is this same type.  Otherwise, the type of
+>       the conditional expression is the single expected type. If there
+>       is no ELSE part, each dependent expression shall resolve to a boolean
+>       type.
+
+I'm not sure this is wise.  I think you might be better to leave it unstated.
+We don't want to say that the type of the conditional expression is T in a
+dispatching call with expected type T, but actual dependent expressions of type
+T'Class.  But maybe it is necessary to specify the type of the conditional
+expression as a whole.  It would be interesting to see in what context the RM
+requires there be a single well-defined type for a given expression, and what
+would be the appropriate answer in these cases.
+
+
+****************************************************************
+
+From: Steve Baird
+Sent: Monday, April 13, 2009 11:26 AM
+
+Do we want to allow, for example,
+    X : Some_Limited_Type := (if ... then  ... else ...); ?
+
+7.5(2.1/2) says:
+   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:
+
+and then the build-in-place contexts are listed in the next few paragraphs.
+
+Should conditional expressions be added to 7.5(2.1/2)?
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, April 13, 2009 12:18 PM
+
+I think yes, why not?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Thursday, April 16, 2009  3:19 PM
+
+> Should conditional expressions be added to 7.5(2.1/2)?
+
+I'm not sure.  It's not trivial to implement in GNAT.  It's not very useful --
+I'll bet most conditionals will be of types like Boolean and String.
+
+If we do allow it, we need to restrict it to having dependent expressions that
+are allowed, so we need the same recursion used for qualified expressions
+("whose operand is permitted...").
+
+If we do not allow it, I suggest we add a rule outlawing conditional expressions
+of limited types altogether.  Otherwise, they will be allowed in some places
+(actual parameters) and not others (initial value of variable), which seems
+inconsistent.  No great loss to outlaw them, IMHO.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, April 22, 2009  6:45 AM
+
+Conditional expressions are now fully implemented and tested with the latest
+development version of GNAT (you have to use the -gnatX language extensions
+switch to get them).
+
+The form is
+
+   (if cond then expr [elsif cond then expr] else expr)
+
+with provision for leaving out the parens in contexts where parens are present
+anyway (parameters for procedures, pragmas, arguments of type conversion, type
+qualifications).
+
+They are really nice (we are making full use of them in the run-time, though
+cannot do that in the compiler proper for years because of bootstrap issues).
+
+As with any expression feature like this, you have to be judicious
+
+   (if Leap_Year then 1 else 2)
+
+is really nice, but heavy nesting with complex conditions and expressions makes
+for a mess!
+
+Thought .. shouldn't we also have case expressions while we are at it, syntax is
+obvious
+
+   (case x is when expr => expr {when expr => expr})
+
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, June 8, 2009  9:37 PM
+
+I'm not going to have time to update the conditional expression AI before
+leaving for the meeting tomorrow.
+
+However, I have an action item to explain my discomfort with the idea of not
+requiring parenthesis around conditional expressions (outside of qualified
+expressions). I realize that I won't be able to explain this in any useful way
+verbally; examples are needed. So let me give some examples.
+
+My concerns center on readability and on syntax error detection. Without the
+parens, it will be hard to tell between a conditional expression and an
+if_statement, both for humans and for compilers.
+
+Let's assume that parens are not required for actual parameters in calls.
+Both of the following could be legal. One isn't indented correctly. Which is it?
+
+    My_Package.Long_Procedure_Name (
+       Object1,
+       Object2 /= Function_Call(10));
+       if Object3 > Func1(100) + Func2(Object1) then
+          Subprog (Object4);
+       else
+          Subprog (Object2);
+       end if;
+
+vs.
+
+    My_Package.Long_Procedure_Name (
+       Object1,
+       Object2 /= Function_Call(10),
+       if Object3 > Func1(100) + Func2(Object1) then
+          Subprog (Object4)
+       else
+          Subprog (Object2));
+
+The only clue is the extra semicolons after the statements (vs. the
+expressions) until you get to the missing "end if". Parens would at least help
+differentiate the latter from the former much earlier in the reading.
+
+More importantly is the detection of syntax errors. A mistake I commonly make
+when cutting and pasting is failing to close the subprogram call properly. The
+problem here is that the difference between a conditional expression and a if
+statement is so minor that the error is likely to be diagnosed pages away from
+the real error location.
+
+    My_Package.Long_Procedure_Name (
+       Object1,
+       Object2 /= Function_Call(10),
+    if Object3 > Func1(100) + Func2(Object1) then
+       Subprog (Object4);
+    else
+       Subprog (Object2);
+    end if;
+
+The syntax error will not be diagnosed until the semicolon after subprogram call
+using Object4, as the syntax up to this point is legal. In this example, that is
+two lines away from the actual error, but of course the condition can be many
+lines long.
+
+If the conditional expression required parens, some error would be detected as
+soon as "if" is encountered, which is right at the point of the error.
+
+I realize the error detection in the Janus/Ada parser is pretty primitive, but I
+don't see any way for any LALR(1) parser to figure out where the error *really*
+is in the above. That's because the various incomplete constructs aren't (yet)
+identified on the parse stack -- it's just a pile of terminals and non-terminals
+-- so study of the state of the parse will not provide much information about
+the problem. (An LL parser might have a better chance since it knows what
+constructs its looking for.)
+
+Existing cases of this sort of problem in Ada ("is" vs. ";" after a subprogram
+definition, for instance) are a never-ending annoyance, and I'd really prefer
+that we avoid adding similar cases to the language.
+
+If the syntax is not going to be identical (and that isn't really a
+possibility), it probably ought to be visually different, especially at the
+start. I'm not sure how to best reconcile that with the desire to be familiar to
+programmers - gratious differences also will be annoying. We could have used
+square brackets here, but that seems pretty radical. More thought is required
+here.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, June 14, 2009  1:27 PM
+
+> However, I have an action item to explain my discomfort with the idea
+> of not requiring parenthesis around conditional expressions (outside
+> of qualified expressions). I realize that I won't be able to explain
+> this in any useful way verbally; examples are needed. So let me give some examples.
+
+I disagree pretty strongly as follows (note this is from the perspective of a
+user, GNAT implements conditional expressions fully, and I have started to use
+them pretty extensively).
+
+> My concerns center on readability and on syntax error detection.
+> Without the parens, it will be hard to tell between a conditional
+> expression and an if_statement, both for humans and for compilers.
+>
+> Let's assume that parens are not required for actual parameters in calls.
+> Both of the following could be legal. One isn't indented correctly.
+> Which is it?
+>
+>     My_Package.Long_Procedure_Name (
+>        Object1,
+>        Object2 /= Function_Call(10));
+>        if Object3 > Func1(100) + Func2(Object1) then
+>           Subprog (Object4);
+>        else
+>           Subprog (Object2);
+>        end if;
+>
+> vs.
+>
+>     My_Package.Long_Procedure_Name (
+>        Object1,
+>        Object2 /= Function_Call(10),
+>        if Object3 > Func1(100) + Func2(Object1) then
+>           Subprog (Object4)
+>        else
+>           Subprog (Object2));
+
+Well
+
+a) improperly indented code is always hard to read, and is
+    basically unacceptable.
+
+b) a good compiler has options to check indentation anyway
+    GNAT will complain loudly about improperly indented code,
+    so a reader will never encounter such!
+
+> The only clue is the extra semicolons after the statements (vs. the
+> expressions) until you get to the missing "end if". Parens would at
+> least help differentiate the latter from the former much earlier in the reading.
+
+I see no advantage in parens here in making something readable that should never
+be written (or tolerated by the compiler) in the first place.
+
+> More importantly is the detection of syntax errors. A mistake I
+> commonly make when cutting and pasting is failing to close the
+> subprogram call properly. The problem here is that the difference
+> between a conditional expression and a if statement is so minor that
+> the error is likely to be diagnosed pages away from the real error location.
+>
+>     My_Package.Long_Procedure_Name (
+>        Object1,
+>        Object2 /= Function_Call(10),
+>     if Object3 > Func1(100) + Func2(Object1) then
+>        Subprog (Object4);
+>     else
+>        Subprog (Object2);
+>     end if;
+
+Well it would be easy enough to special case this if it really arises in
+practice (we will wait for a user report!) I have never run into this in my use
+of conditional expressions.
+
+> The syntax error will not be diagnosed until the semicolon after
+> subprogram call using Object4, as the syntax up to this point is
+> legal. In this example, that is two lines away from the actual error,
+> but of course the condition can be many lines long.
+>
+> If the conditional expression required parens, some error would be
+> detected as soon as "if" is encountered, which is right at the point of the error.
+>
+> I realize the error detection in the Janus/Ada parser is pretty
+> primitive, but I don't see any way for any LALR(1) parser to figure
+> out where the error
+> *really* is in the above. That's because the various incomplete
+> constructs aren't (yet) identified on the parse stack -- it's just a
+> pile of terminals and non-terminals -- so study of the state of the
+> parse will not provide much information about the problem. (An LL
+> parser might have a better chance since it knows what constructs its
+> looking for.)
+
+Ada is designed to be easy to read, I do not consider designing so that a
+naively written parser can give good error messages to be a significant factor
+in the language design.
+
+> Existing cases of this sort of problem in Ada ("is" vs. ";" after a
+> subprogram definition, for instance) are a never-ending annoyance, and
+> I'd really prefer that we avoid adding similar cases to the language.
+
+GNAT has special circuitry that shows that this problem can be handled just
+fine, GNAT in practice accurately diagnoses the misuse of IS for semicolon and
+vice versa, so at least with GNAT this is not a "never-ending annoyance", it is
+not an annoyance at all.
+
+> If the syntax is not going to be identical (and that isn't really a
+> possibility), it probably ought to be visually different, especially
+> at the start. I'm not sure how to best reconcile that with the desire
+> to be familiar to programmers - gratious differences also will be
+> annoying. We could have used square brackets here, but that seems
+> pretty radical. More thought is required here.
+
+I disagree that more thought is required, I find the proposal as it is
+convenient to use, and convenient to read, and I would really find the double
+parens to be an irritation.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Sunday, June 14, 2009  3:44 PM
+
+FWIW, I find:
+
+    Some_Procedure ((if X then Y else Z));
+
+in the case where there's just one param, to have mildly annoying "extra"
+parens.  This seems better:
+
+    Some_Procedure (if X then Y else Z);
+
+On the other hand, when there are 2 or more params:
+
+    Some_Procedure (Mumble, (if X then Y else Z), Dumble);
+
+the "extra" parens seem helpful, as compared to:
+
+    Some_Procedure (Mumble, if X then Y else Z, Dumble);
+
+Whatever we do, let's not let this minor issue derail the conditional
+expressions proposal!  I can live with most of the various alternative proposed
+syntaxes.  (And I can add style checks to GNAT if desired...)
+
+After careful consideration of Randy's and other's notes, my strong opinion is:
+I don't care.  ;-)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, June 14, 2009  4:00 PM
+
+> FWIW, I find:
+>
+>     Some_Procedure ((if X then Y else Z));
+>
+> in the case where there's just one param, to have mildly annoying "extra"
+> parens.  This seems better:
+>
+>     Some_Procedure (if X then Y else Z);
+
+I agree, but find the extra parens *more* than mildly annoying, I find them
+really annoying, especially in the context of
+
+       pragma Precondition (if X > 0 then Y / X > 3);
+
+> On the other hand, when there are 2 or more params:
+>
+>     Some_Procedure (Mumble, (if X then Y else Z), Dumble);
+
+I agree
+
+> the "extra" parens seem helpful, as compared to:
+>
+>     Some_Procedure (Mumble, if X then Y else Z, Dumble);
+
+I agree, but would not legislate this, let it be a matter of appropriate style,
+and I am not sure about the case:
+
+>      Some_Procedure (Subject => Mumble,
+                       Flag    => if X then Y else Z,
+                       Data    => Dumble);
+
+Here the extra parens seem unnecessary to me
+
+> Whatever we do, let's not let this minor issue derail the conditional
+> expressions proposal!  I can live with most of the various alternative
+> proposed syntaxes.  (And I can add style checks to GNAT if desired...)
+
+Indeed
+
+> After careful consideration of Randy's and other's notes, my strong opinion is:
+> I don't care.  ;-)
+
+I think at this stage we would not change GNAT, since we now have a lot of code
+using the proposed style with optional parens in the parameter case (of course
+we require the -gnatX switch to enable extensions :-)) but if the ARG decides to
+always require double parens, we can do this under --pedantic or some style
+switch for ACATS purposes :-)
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Monday, June 15, 2009  12:41 AM
+
+> However, I have an action item to explain my discomfort with the idea of not
+> requiring parenthesis around conditional expressions (outside of qualified
+< expressions). I realize that I won't be able to explain this in any useful
+> way verbally; examples are needed. So let me give some examples.
+
+I must confess that I didn't read the entire thread on conditional expressions,
+but I share Randy's discomfort.  I am not particularly in love with requiring
+parentheses around these expressions, but I believe that there has to be a
+closing delimiter somehow, otherwise you end up with awful syntax headaches.
+Consider:
+
+A := if B then C else D + 1;
+
+It is quite unclear for the human reader how the "+ 1" binds.  I believe that,
+since a conditional_expression is a primary, it actually binds as (if B then C
+else D) + 1, which is the worst possible outcome.  But I am not even sure that
+my understanding of the grammar is correct.
+
+Also, without a closing delimiter, you end up with the dreaded "dangling else
+problem" of C:
+
+A := if B then if C then D else E;
+
+Again, it is possible to define how the "else" binds (C does it) but that
+doesn't help readability.
+
+As much as I hate extra parentheses, I think that they are better than the above
+ambiguities.  Either that, or put "end" or "end if" at the end of the
+expression.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, June 15, 2009  9:54 AM
+
+Although I favored some special-casing to eliminate duplicate parentheses, I
+agree that the value of the feature vastly outweighs any slight aesthetic
+concerns with double parentheses.
+
+If we do decide to somehow special case this, I think we do need to worry about
+error recovery as Randy has, and we should think about how this generalizes, if
+at all, to aggregates and other uses of parentheses (such as the "sequence"
+notation we discussed at Brest of "(A | B | C)" ).
+
+Extra spaces or named notation can to some degree lessen the aesthetic concern:
+
+    Foo( (if A then B else C) );
+
+  or
+
+    Foo(Param => (if A then B else C));
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, June 17, 2009  2:20 PM
+
+> I must confess that I didn't read the entire thread on conditional
+> expressions, but I share Randy's discomfort.  I am not particularly in
+> love with requiring parentheses around these expressions, but I
+> believe that there /has /to be a closing delimiter somehow, otherwise
+> you end up with awful syntax headaches.  Consider:
+>
+> A := if B then C else D + 1;
+
+This seems an irrelevant concern, no one has even vaguely suggested not
+requiring the parens in this case. The cases where we leave out parens are
+limited to subprogram parameters, and pragma arguments, where we do have
+delimiters, and in particular in the case of one param, the delimiters are an
+extra set of parens.
+
+> It is quite unclear for the human reader how the "+ 1" binds.  I
+> believe that, since a conditional_expression is a primary, it actually
+> binds as (if B then C else D) + 1, which is the worst possible
+> outcome.  But I am not even sure that my understanding of the grammar is
+> correct.
+
+Again, not to worry, no one thinks this is an issue that should be addressed.
+
+> Also, without a closing delimiter, you end up with the dreaded
+> "dangling else problem" of C:
+>
+> A := if B then if C then D else E;
+
+Again, no one suggests allowing this syntax, and e.g. in a procedure call we
+would require
+
+    P (if B then (if C then D else E));
+
+> Again, it is possible to define how the "else" binds (C does it) but
+> that doesn't help readability.
+>
+> As much as I hate extra parentheses, I think that they are better than
+> the above ambiguities.  Either that, or put "end" or "end if" at the
+> end of the expression.
+
+Well I think what we need is your reaction to the actual proposal, rather than
+to one that is obviously unworkable which no one has proposed :-)
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, June 17, 2009  2:40 PM
+
+> This seems an irrelevant concern, no one has even vaguely suggested
+> not requiring the parens in this case. The cases where we leave out
+> parens are limited to subprogram parameters, and pragma arguments,
+> where we do have delimiters, and in particular in the case of one
+> param, the delimiters are an extra set of parens.
+
+Are those the only cases?
+
+I find the pragma Precondition example (and other assertions) to be a strong
+argument for allowing to omit the extra parens.  After all, one of the main
+purposes of this conditional exp feature is to express implication, given that
+folks won't let me add the "implies" operator to the language.  ;-)
+
+I would be happy with a rule that requires parens in a call if there is more
+than one actual param.  Either as a language rule (a syntax rule, written in
+English, rather than BNF), or as an implementation-defined style check.
+
+> > It is quite unclear for the human reader how the "+ 1" binds.  I
+> > believe that, since a conditional_expression is a primary, it
+> > actually binds as (if B then C else D) + 1, which is the worst
+> > possible outcome.  But I am not even sure that my understanding of the
+> > grammar is correct.
+>
+> Again, not to worry, no one thinks this is an issue that should be
+> addressed.
+>
+> > Also, without a closing delimiter, you end up with the dreaded
+> > "dangling else problem" of C:
+> >
+> > A := if B then if C then D else E;
+>
+> Again, no one suggests allowing this syntax, and e.g. in a procedure
+> call we would require
+>
+>     P (if B then (if C then D else E));
+
+or:
+
+    P (if B then (if C then D) else E);
+
+Right?
+
+These are allowed only when the type is boolean, so "else False" is implicit.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, June 17, 2009  2:52 PM
+
+> Are those the only cases?
+
+Maybe conversions and qualified expressions, can't remember now?
+No big deal either way for those two cases I would say, but they are double
+paren cases.
+
+> I find the pragma Precondition example (and other assertions) to be a
+> strong argument for allowing to omit the extra parens.  After all, one
+> of the main purposes of this conditional exp feature is to express
+> implication, given that folks won't let me add the "implies" operator
+> to the language.  ;-)
+
+I agree
+
+> I would be happy with a rule that requires parens in a call if there
+> is more than one actual param.  Either as a language rule (a syntax
+> rule, written in English, rather than BNF), or as an implementation-defined
+> style check.
+
+Yes, I could live with that, although I find
+
+     Proc1 (x => 3, y => if bla then 3 else 2)
+
+fine
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, June 17, 2009  2:54 PM
+
+> These are allowed only when the type is boolean, so "else False" is implicit.
+
+Since we want "if A then B" to be equivalent to "A => B", "else true" is
+implicit.  "else false" would make it equivalent to "A and then B" which is not
+very useful.
+
+If you write it in an assertion or a precondition, it becomes clear that you
+mean "else True":
+
+    Assert (if A then B [else True])
+
+    Pre => (if A then B [else True])
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, June 17, 2009  3:20 PM
+
+Indeed, when you say
+
+       pragma Precondition (if A then B);
+       --  Current implemented GNAT syntax, subject to change :-)
+
+you are saying that if A is true then B must hold, otherwise you don't have any
+precondition (which means True).
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, June 17, 2009  4:01 PM
+
+> > These are allowed only when the type is boolean, so
+> > "else False" is implicit.
+          ^^^^^ Typo for True.  Think-o, really.  ;-)
+
+> Since we want "if A then B" to be equivalent to "A => B", "else true"
+> is implicit.  "else false" would make it equivalent to "A and then B"
+> which is not very useful.
+
+Right.  Thanks for the correction.  I meant "else True".
+
+> If you write it in an assertion or a precondition, it becomes clear
+> that you mean "else True":
+>
+>     Assert (if A then B [else True])
+>
+>     Pre => (if A then B [else True])
+
+Right.  Robert may use my momentary confusion as evidence that "the 'implies'
+op is confusing".  [Note deliberate ambiguous use of "may".]
+
+I'm embarrassed.  I promise you: I didn't flunk my Mathematical Logic course,
+and I really do know what "implies" means, deep down in my heart!  ;-)
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, June 17, 2009  4:03 PM
+
+> Yes, I could live with that, although I find
+>
+>      Proc1 (x => 3, y => if bla then 3 else 2)
+>
+> fine
+
+Shrug.  I could live with that, or I could live with a requirement (or style
+rule) for:
+
+     Proc1 (x => 3, y => (if bla then 3 else 2))
+
+Right now I find the latter preferable, but I could change my mind tomorrow.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, June 17, 2009  4:05 PM
+
+> Indeed, when you say
+>
+>        pragma Precondition (if A then B);
+>        --  Current implemented GNAT syntax, subject to change :-)
+>
+> you are saying that if A is true then B must hold, otherwise you don't
+> have any precondition (which means True).
+
+Right.  Sorry again for my momentary stupidity!
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, June 17, 2009  4:19 PM
+
+> Right now I find the latter preferable, but I could change my mind tomorrow.
+
+I have no strong preference on this one, so if people will be more amenable to
+the no parens in the single param case if we remove it for the double param
+case, that's fine.
+
+In fact I kind of like the rule that you need parens unless the expression is
+already enclosed in parens. So that all we ever do is avoid double parens.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Wednesday, June 17, 2009  4:24 PM
+
+>> Yes, I could live with that, although I find
+>>
+>>      Proc1 (x => 3, y => if bla then 3 else 2)
+>>
+>> fine
+>
+> Shrug.  I could live with that, or I could live with a requirement (or
+> style
+> rule) for:
+>
+>      Proc1 (x => 3, y => (if bla then 3 else 2))
+
+My concern with these proposals to remove the parentheses is how hard it will be
+to explain, both to users and in the language definition. The current proposal
+is "same rule as aggregates", i.e. extra parentheses omitted only for qualified
+expressions. This is an easy rule. And yes, if you pass an aggregate as the only
+parameter to a procedure, you have double parentheses, and nobody complained
+about that.
+
+I have some sympathy to removing the parentheses for pragma assert, but how can
+you /simply/ put that into the language?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, June 17, 2009  5:16 PM
+
+> My concern with these proposals to remove the parentheses is how hard
+> it will be to explain, both to users and in the language definition.
+
+Both are important concerns, but in this case, it's not such a big deal:
+
+The user-view is simple.  Put in parens where needed for readable code.
+Then, if the compiler complains about missing parens, put them in.
+
+The lang-def issue is also no big deal.  Nobody but language lawyers read it, so
+it can be arcane, so long as it's precise.
+
+>...The
+> current proposal is "same rule as aggregates", i.e. extra parentheses
+>omitted only for qualified expressions. This is an easy rule.
+
+Yes.
+
+>...And yes,
+> if you pass an aggregate as the only parameter to a procedure, you
+>have  double parentheses, and nobody complained about that.
+
+The aggregate case is different, I think.  There, the parens actually do
+something (gather up all those components into a bigger thing).
+
+> I have some sympathy to removing the parentheses for pragma assert,
+> but how can you /simply/ put that into the language?
+
+Good question.  I think the answer is: make the BNF syntax fairly simple, and
+add some English-language rules, saying something like "if there is more than
+one arg, any conditional exp must have parens".  Or make it conditional upon
+named notation, if that's desired.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Wednesday, June 17, 2009  5:37 PM
+
+> The user-view is simple.  Put in parens where needed for readable code.
+> Then, if the compiler complains about missing parens, put them in.
+
+Well this presumes that the compiler is always clever enough to recognize a
+conditional expression without parens as such.
+
+I prefer a user-view that says, enclose a conditional expression in parens
+except you can leave out the parens if the conditional expression is already
+enclosed in parens, e.g. when it appears as the sole argument to a subprogram.
+
+****************************************************************
+
+From: Pascal Leroy
+Sent: Thursday, June 18, 2009  5:22 PM
+
+> This seems an irrelevant concern, no one has even vaguely suggested
+> not requiring the parens in this case. The cases where we leave out
+> parens are limited to subprogram parameters, and pragma arguments,
+> where we do have delimiters, and in particular in the case of one
+> param, the delimiters are an extra set of parens.
+
+Whatever the rules, I would hope that conversions, slices, and array components
+are handled similarly to subprogram calls.  That is, if I am able to omit
+parentheses in:
+
+X := Fun(if A then B else C);
+
+I should be able to omit them in:
+
+X := Arr(If Backwards then Arr'Last else Arr'First);
+
+Breaking the syntactic similarity between these constructs would be silly.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Friday, June 19, 2009  12:36 PM
+
+> X := Fun(if A then B else C);
+>
+> I should be able to omit them in:
+>
+> X := Arr(If Backwards then Arr'Last else Arr'First);
+>
+> Breaking the syntactic similarity between these constructs would be silly.
+
+I agree entirely. I really lean now to the solution that says you can omit
+parens only in the double parens cases, which would of course include the type
+conversion and qualified expression cases.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Friday, June 19, 2009  12:46 PM
+
+I presume we are *not* generalizing this to aggregates, as that could create
+some real ambiguity.  That is, this is not some general rule that anyplace you
+find yourself with two sets of parentheses you can replace them with one.  For
+example:
+
+     Fun((A => 3, B => 4))
+
+cannot be replaced by:
+
+     Fun(A => 3, B => 4)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Friday, June 19, 2009  1:02 PM
+
+Right, that obviously won't work for aggregates, so this would be JUST for
+conditional expressions.
+
+P.S. A thought about conditional expressions and Implies
+
+If I write
+
+    if A then B end if;
+
+it has the feeling of "nothing if A is false"
+
+If I write
+
+    pragma Precondition (if A then B);
+
+then that same feeling carries over nicely, this really can be thought of as
+
+    if A then pragma Precondition (b) else nothing
+
+and so that's nicely parallel, and in fact I like that much better than
+
+    pragma precondition (A => B);
+
+But if we use this in some other context
+
+    if (if B then C) then ...
+
+I really can't understand that any more, so I think my coding standard would
+allow omission of the else only in the pre/postcondition usages.
+
+I can understand
+
+    if B implies C then ...
+
+a bit better, but I still have to think about it, so I still prefer not to
+introduce an implies operator.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Friday, June 19, 2009  1:21 PM
+
+> But if we use this in some other context
+>
+>    if (if B then C) then ...
+>
+> I really can't understand that any more, so I think my coding standard
+> would allow omission of the else only in the pre/postcondition usages.
+
+That seems a bit overly stringent.  I think it is also well defined in pragma
+Assert, or in calling a function which is the rough equivalent of Assert.  I
+could see disallowing it when used as the condition of an "if" or "while"
+statement, or when combined into a more complex expression such as:
+
+    Assert((if B then C) or else (D and E));
+
+> I can understand
+>
+>    if B implies C then ...
+>
+> a bit better, but I still have to think about it, so I still prefer
+> not to introduce an implies operator.
+
+Agreed.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Friday, June 19, 2009  2:02 PM
+
+> That seems a bit overly stringent.  I think it is also well defined in
+> pragma Assert, or in calling a function which is the rough equivalent
+> of Assert.
+
+Yes, of course Assert is just like PPC's, and indeed a subprogram acting like
+Assert would also meet this general feeling (do nothing in the else case)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, January 18, 2010  11:12 PM
+
+Last spring we discussed various resolution rules, without ever quite coming to
+a conclusion. I think we ran out of energy before actually reaching an answer.
+I'd like your thoughts on my current ideas.
+
+The model for conditional expressions is that it is a particularly fancy set of
+parentheses. Figuring out the correct rules for that is challenging, in large
+part because there are no rules that describe how parentheses work in the normal
+case.
+
+The main problem with the rules that were previously proposed is that they
+didn't work properly in the face of implicit conversion. That occurred about of
+various attempts to talk about the type of the dependent_expressions, especially
+to figure out the type of the construct as a whole.
+
+On this last point, I can't find any reason to actually specify such a type. I
+can't find any wording that ever says what the type of an aggregate is, for
+instance. The only sort of definition that I can find is the nominal subtype,
+but that is only defined for names. Memberships do define a "result type" of
+Boolean, but "result type" seems to be only defined for operations, operators,
+and function calls.
+
+But this seems more to be a hole in the existing wording than a feature. Rules
+like 4.3.2(5/2) require knowing something about the expression. (This particular
+case is not a problem in the existing language, though: an extension aggregate
+ancestor expression can't be a non-qualified aggregate as no type could be
+identified. But that wouldn't be true for a conditional expression.)
+
+Even so, that type doesn't need to be defined in the Name Resolution Rules. Nor
+do any of the other rules necessarily need to apply to the resolution of a
+conditional expression; they can be separate legality rules.
+
+Thus, I would like to propose that the Name Resolution Rule for conditional
+expressions be simply:
+
+    The expected type for each dependent_expression of a conditional_expression
+    is the expected type of the conditional_expression as a whole.
+
+Followed by some Legality Rules that I'll get to in a minute.
+
+Unfortunately, this wording doesn't work for expressions that don't have an
+expected type. Those occur in renames and qualified expressions: those are
+contexts that don't allow implicit conversion. Qualified expressions use "the
+operand shall resolve to be of the type determined by the subtype_mark, or a
+universal_type that covers it". (Object renames are similar.) Thus dynamically
+tagged expressions aren't allowed, nor are the implicit conversion associated
+with anonymous access types.
+
+(Aside: Tucker's new wording for non-memberships [8.6(27.1/3), from AI-102 and
+AI-149] which requires convertibility, seems to assume that expressions have
+expected types. The rule doesn't need to apply to "shall resolve to" cases
+(since the same type is obviously convertible), but there is nothing that makes
+that clear. I just added a Ramification note, but I'm not sure if that is
+sufficient.]
+
+So we need slightly more complex wording:
+
+    If a conditional_expression has an expected type T, the expected type for
+    each dependent_expression of a conditional_expression is T. If a
+    conditional_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).
+
+Then we need some legality rules:
+
+    Legality Rules
+
+    If the expected type of a conditional_expression is any type in a class of
+    types (instead of a particular type), all dependent_expressions of the
+    conditional_expression shall have the same type.
+
+    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, and is statically tagged
+    otherwise.
+
+[We need this latter rule to be able to enforce 3.9.2(8); we don't want the parameter of a dispatching call to have mixed static and dynamic tagging. We could have written this in terms of dispatching calls instead, but 3.9.2(9/1) makes other uses of dyna
mically tagged expressions illegal.]
+
+The first rule is needed to avoid expressions with different types in the
+different branches. (Note the we don't need to talk about "single types" here,
+as that is a property of constructs, not contexts; we're only talking about
+contexts here.) For instance, this rule would make the following illegal
+(although it would resolve):
+
+    type Some_Boolean is new Boolean;
+    function Foo return Some_Boolean;
+
+    Cond : Boolean := ...;
+    Var  : Natural := ...;
+
+    if (if Cond then Var > 10 else Foo) then ... -- Illegal by legality rule.
+
+Note that this formulation would make some things ambiguous that would resolve
+by looking at other expressions:
+
+    function ">" (A, B : Natural) return Some_Boolean;
+
+    if (if Cond then Var < 10 else Var > 20) then ... -- ">" is ambiguous;
+         -- the fact that only one interpretation would pass the legality rule is irrelevant.
+
+I think this ambiguity is in keeping with the analogy to parens; the expression
+would be ambiguous if written as statements:
+
+    if Cond then
+        if (Var < 10) then ...
+    else
+        if (Var > 20) then ... -- ">" is ambiguous
+    end if;
+
+Because of this, I can't get too concerned.
+
+The legality rule does have the effect that if any implicit conversions apply in
+such a case, they all have to be the same. I haven't been able to think of any
+realistic case where that would matter; usually such expressions would be
+ambiguous anyway.
+
+
+Note that we don't have a similar rule that applies when the expected type is a
+particular type. That allows the branches to have expressions that are different
+implicit conversions. For instance:
+
+    type T is tagged ...;
+    type NT is new T with ...;
+    Tobj : T;
+    NTObj : NT;
+
+    function Bar return T'Class is
+    begin
+        return (if Cond then Tobj else NTObj); -- Legal.
+        if Cond then -- Legal.
+           return Tobj;
+        else
+           return NTObj;
+        end if;
+    end Bar;
+
+Again, this allows a similar analogy.
+
+In all such cases, the types have to be related or the expression wouldn't have
+resolved (the expected types are the same, after all). So I don't think this is
+weird, indeed it seems necessary to deal properly with anonymous access types
+(and especially the literal "null").
+
+One case that has bothered me was that type conversions fail this principle:
+
+         Var := Natural (if Cond then 10 else 1.5);
+
+The type conversions would be legal separately, but since this isn't a context
+with a particular expected type, the types must match and these don't. This is
+easily fixed (move the type conversions inside of the conditional expression),
+so I don't think this is important.
+
+I'm sure at this point that Steve or Bob will come up with a dozen examples of
+why this doesn't work. Fire away. :-)
+
+
+---
+
+A related issue is build-in-place for conditional expressions.
+
+I believe that the implementation model for objects that are required to be
+built-in-place is not too bad. Consider:
+
+    type Some_ImmLim_Type is limited tagged ...
+    function Glarch (I : Natural) return Some_ImmLim_Type;
+
+    Obj : Some_ImmLim_Type := (if Cond then Glarch(1) else Glarch(2));
+
+In a case like this, the address of Obj would be passed to the conditional
+expression, and given to whatever dependent_expression actually is evaluated.
+This might be a bit messy, but it doesn't appear to be intractable.
+
+What bothers me is what happens if the expression has some expressions would
+normally be built-in-place, and some that would not. Consider:
+
+    type Some_Type is record C : Natural; ...
+    function Blob return Some_Type;
+
+    Obj1 : Some_Type := (if Cond then Blob else Some_Type'(C => 1, ...));
+
+If the implementation always builds aggregates in place, and never does that for
+function calls, the conflict in calling conventions could be messy to deal with.
+
+I'm not sure if this is a real problem: if some expression uses build-in-place,
+just build it into an anonymous object and assign that when needed.
+
+So, for the moment, I'm going to allow build-in-place for conditional
+expressions.
+
+---
+
+Thanks for reading this lengthy discussion.
+
+****************************************************************

Questions? Ask the ACAA Technical Agent