CVS difference for ai05s/ai05-0153-3.txt

Differences between 1.1 and version 1.2
Log of other versions for file ai05s/ai05-0153-3.txt

--- ai05s/ai05-0153-3.txt	2010/10/26 02:39:17	1.1
+++ ai05s/ai05-0153-3.txt	2011/01/25 07:18:09	1.2
@@ -1,4 +1,4 @@
-!standard  3.2.4(0)                                10-10-08    AI05-0153-3/01
+!standard  3.2.4(0)                                11-01-23    AI05-0153-3/02
 !class Amendment 09-05-27
 !status work item 09-05-27
 !status received 09-05-27
@@ -16,10 +16,10 @@
 In many ways, predicates are similar to, but more general than,
 constraints.
 
-If a predicate obeys certain restrictions, the subtype is considered
-static, and can therefore be used as a choice in case statements
-and the like. 'for' loops are also defined over static subtypes
-with predicates.
+There are two predicate aspects: Static_Predicate and Dynamic_Predicate.
+Static_Predicates must obey certain restrictions, and the subtype can be
+static, so it be used as a choice in case statements and the like.
+'for' loops are also defined over subtypes with static predicates.
 
 !problem
 
@@ -27,7 +27,7 @@
 object (including formal parameters). But the constraints that can
 be expressed are limited.
 
-For instance, it isn't possible to specify that a record type may
+For instance, it isn't possible to specify that a record subtype may
 have any of several discriminant values -- for discriminants we can
 only specify a single value or allow all discriminants. Similarly,
 it isn't possible for a subtype to define a noncontiguous subset of
@@ -37,23 +37,30 @@
 
 !proposal
 
-We define a new aspect "Predicate", which takes a condition (i.e. a
-BOOLEAN_expression). The condition can use the defining_identifier of the
-subtype to mean the "current instance" of the subtype (that is, the object to
-test the predicate against), as defined in AI05-0183-1.
-For example:
+We define two new aspect predicate aspects, "Static_Predicate" and
+"Dynamic_Predicate", which take a condition (i.e. a BOOLEAN_expression). The
+condition can use the defining_identifier of the subtype to mean the "current
+instance" of the subtype (that is, the object to test the predicate against),
+as defined in AI05-0183-1.
+
+The difference between Static_Predicate and Dynamic_Predicate is that in the
+former case, the expression is restricted to certain sort-of-static forms,
+which allows such subtypes to be used in situations requiring static subtypes,
+such as in case statements.
+
+Example:
 
     type T is ...;
     function Is_Good(X: T) return Boolean;
     subtype Good_T is T with
-        Predicate => Is_Good(Good_T);
+        Dynamic_Predicate => Is_Good(Good_T);
 
 Good_T conceptually represents the subset of values of type T for
 which Is_Good returns True.
 
-A Predicate may be given on a subtype_declaration,
+A predicate may be given on a subtype_declaration,
 in which case it applies to that subtype.
-A Predicate may also be given on a type_declaration,
+A predicate may also be given on a type_declaration,
 in which case it applies to the first subtype.
 
 The predicate is checked at certain places, such as assignment
@@ -64,23 +71,23 @@
 be False if the predicate of S is False for X, and (for scalars) "X'Valid" will
 be False if the predicate of S is False for X,
 
-The base subtype always has the Predicate "True".
+The base subtype always has the predicate "True".
 Thus, the 'Base attribute may be used to
 remove the predicate; S'Base means "S without any
 constraint or predicate". (Note that 'Base is allowed
 only for scalars. There is no "remove the predicate"
 feature for nonscalars.)
 
-Scalar subtypes with user-defined Predicates cannot be used in cases
+Scalar subtypes with user-defined predicates cannot be used in cases
 that would make sense only for contiguous subranges -- 'First
 is illegal, use as an array index subtype is illegal, and so on.
 Thus, we avoid anomalies like "S'First in S" being False.
 
-Certain subtypes with Predicates are defined to be static.
+Certain subtypes with Static_Predicates are defined to be static.
 For example,
 
     subtype Letter is Character with
-        Predicate => Letter in 'A'..'Z' | 'a'..'z';
+        Static_Predicate => Letter in 'A'..'Z' | 'a'..'z';
 
 Letter is a static subtype.  (Actually, it should probably include
 things like 'À' -- this is just an example!)
@@ -124,48 +131,63 @@
 
 3.2.4 Subtype Predicates
 
-The language-defined aspect Predicate is defined for subtypes.
+The language-defined "predicate aspects" Static_Predicate and Dynamic_Predicate
+may be used to define properties of subtypes. A "predicate clause" is an aspect
+clause specifying one of the two predicate aspects.
 
 
                              Name Resolution Rules
+
+The expected type for a predicate aspect expression is any boolean type.
+
+
+                               Static Semantics
+
+A predicate clause may be given on a type_declaration or a subtype_declaration,
+and applies to the declared subtype. In addition, predicate clauses apply to
+certain other subtypes:
 
-The expected type for a Predicate expression is any boolean type.
+    - For a (first) subtype defined by a derived type
+      declaration, the predicates of the parent subtype and the
+      progenitor subtypes apply.
 
+    - For a subtype created by a subtype_indication, the
+      predicate of the subtype denoted by the subtype_mark
+      applies.
 
+The "predicate" of a subtype consists of all predicate clauses that apply,
+and-ed together; if no predicate clauses apply, the predicate is True
+Redundant[(in particular, the predicate of a base subtype is True)].
+
                                Legality Rules
 
-A Predicate may be specified on a type_declaration or a subtype_declaration; if
-none is given, an implicit "with Predicate => True" is assumed.
-The predicate of a subtype is defined as follows:
+The expression of a Static_Predicate clause shall be "predicate-static";
+that is, one of the following:
 
-    - For a (first) subtype defined by a derived type declaration, the
-      specified Predicate, and-ed with the predicate of the parent subtype,
-      and-ed with the predicates of the progenitor subtypes.
+    - a static expression that does not raise any exception;
 
-    - For a (first) subtype defined by a non-derived type declaration,
-      the specified Predicate.
+    - a membership test whose left-hand side is the current instance,
+      and whose right-hand side is static;
+[Author's Question: Does that allow "S in (Foo | Bar | Baz)"?]
 
-    - For a subtype created by a subtype_declaration, the specified Predicate,
-      and-ed with the predicate of the subtype denoted by the subtype_mark.
+    - a call to a predefined equality or ordering operator, where one operand
+      is the current instance, and the other is a static expression;
 
-    - For a subtype created by a subtype_indication that is not that of
-      a subtype_declaration, the predicate of the subtype denoted by the
-      subtype_mark.
+    - a call to a predefined boolean logical operator, where both operands
+      are predicate-static; or
 
-    - For a base subtype, True.
+    - a parenthesized predicate-static expression.
 
 An index subtype, discrete_range of an index_constraint or slice, or a
 discrete_subtype_definition of a constrained_array_definition,
 entry_declaration, or entry_index_specification shall not denote a
-subtype with a user-specified predicate.
+subtype to which predicate clauses apply.
 
-The discrete_subtype_definition of a loop_parameter_specification shall not
-denote a subtype with a user-specified predicate, unless the subtype is
-static.
+The prefix of an attribute_reference whose attribute_designator is First, Last,
+or Range shall not denote a subtype to which predicate clauses apply.
 
-The prefix of an attribute_reference shall not denote a subtype with a
-user-specified predicate if the attribute_designator is First, Last,
-or Range.
+The discrete_subtype_definition of a loop_parameter_specification shall not
+denote a subtype to which Dynamic_Predicate clauses apply.
 
 
                                Dynamic Semantics
@@ -207,12 +229,14 @@
 predicate was True.
 
 
-NOTE: A Predicate does not cause a subtype to be considered "constrained".
+NOTE: A predicate clause does not cause a subtype to be considered
+"constrained".
 
-NOTE: A Predicate is not necessarily True for all objects of the subtype at all
+NOTE: A predicate is not necessarily True for all objects of the subtype at all
 times. Predicates are checked as specified above, but can become False at other
-times. For example, the Predicate of a record is not checked when a component is
-modified.
+times. For example, the predicate of a record is not checked when a component
+is modified. Similarly to constraints, predicates can be False for
+uninitialized variables and other invalid values.
 
 [End of 3.2.4.]
 
@@ -247,8 +271,7 @@
       each non-others discrete_choice shall cover only values in that subtype
       {that satisfy the predicate},
       and each value of that subtype {that satisfies the predicate}
-      shall be covered by some discrete_-
-      choice [(either explicitly or by others)];
+      shall be covered by some discrete_choice [(either explicitly or by others)];
 
 Modify 4.5.2(29) so membership tests take the predicate into account:
 
@@ -275,39 +298,18 @@
 If the Assertion_Policy in effect is Check, the predicate of the target subtype
 is applied to the value and Assertions.Assertion_Error is raised if the result
 is False.
-
-Add to the end of 4.9(26/2), so subtypes with predicates of certain
-forms are static:
-
-    Also, a subtype is static only if the predicate is predicate-static.
 
-Add new paragraphs after 4.9(32), to define the term "predicate-static"
-used above in 4.9(26/2):
-
-An expression within a predicate is "predicate-static"
-if it is one of the following:
-
-    - a static expression that does not raise any exception;
-
-    - a membership test whose left-hand side is the current instance,
-      and whose right-hand side is static;
+Add to the end of 4.9(26/2), so subtypes with Static_Predicates can be static,
+but those with Dynamic_Predicate are not:
 
-    - a call to predefined equality or ordering operator, where one operand is
-      the current instance, and the other is a static expression;
+    Also, a subtype is not static if any Dynamic_Predicate clauses apply to it.
 
-    - a call to a predefined boolean logical operator, where both operands
-      are predicate-static; or
-
-    - a parenthesized predicate-static expression.
-
 Modify 4.9.1(2/2), so static matching takes predicates into account:
 
   A subtype statically matches another subtype of the same type if they have
-  statically matching constraints, {all predicate_clauses that apply to them come
-  from the same declarations, }and, for access subtypes, either both or
+  statically matching constraints, {all predicate clauses that apply to them
+  come from the same declarations, }and, for access subtypes, either both or
   neither exclude null. ...
-  [???Should we allow matching for predicates that happen to have all
-  the same values, in the static case?  I think not.]
 
 Modify 4.9.1(4/3), so "statically compatible" takes predicates into account:
 
@@ -323,6 +325,7 @@
   statically compatible with the second only if both subtypes are static, and
   every value that obeys the predicate of the first obeys the predicate of the
   second.}
+[Author's question: Is that reasonable to implement?]
 
 Modify 5.4(7/3), so the full coverage rules for case statements
 take predicates into account:
@@ -361,10 +364,10 @@
 contiguous range. We could relax this somewhat.
 For example, we could allow 'First in the following cases:
 
-    Predicate => True -- which is what you get by default
-    Predicate => 1 > 0 -- static expression with value True
-    Predicate => Cur_Inst in 1..10 -- contiguous range
-    Predicate => Cur_Inst >= 0 -- contiguous range 0..'Base'Last
+    Static_Predicate => True -- which is what you get by default
+    Static_Predicate => 1 > 0 -- static expression with value True
+    Static_Predicate => Cur_Inst in 1..10 -- contiguous range
+    Static_Predicate => Cur_Inst >= 0 -- contiguous range 0..'Base'Last
 
 However, it seems simplest to forbid 'First if there is
 any user-defined predicate.
@@ -398,20 +401,19 @@
 
 This means that "S'(X) in S" could be False if Assertion_Policy is Ignore.
 This is similar to suppressing checks (strange things can happen), but
-far milder, because suppressing checks can cause erroneous behavior,
+milder, because suppressing checks can cause erroneous behavior,
 whereas here, we get True, or False, or Constraint_Error.
 
 ---
 
 Static Predicated Subtypes.
 
-The following operations are allowed in predicate-static expressions:
+The following operations are allowed in Static_Predicate expressions:
 "=", "/=", "<", ">", "<=" ">=", "and", "or", "xor", "not", "in", "not in".
 The following are not: "and then", "or else", "mod", etc -- except that
 these are of course allowed in fully-static subexpressions (i.e. not
 involving the current instance). E.g., "X mod 2" is allowed if X is
-a static constant, but if X is the current instance, then the subtype
-is not static.
+a static constant, but not if X is the current instance.
 
 The purpose of defining some subtypes with user-defined predicates to be static
 is to allow those subtypes in places where the language provides full coverage
@@ -425,11 +427,15 @@
 'A'..'Z' | 'a'..'z'.  We now allow:
 
     subtype Letter is Character with
-        Predicate => Letter in 'A'..'Z' | 'a'..'z';
+        Static_Predicate => Letter in 'A'..'Z' | 'a'..'z';
 
     case Current_Char is
         when Letter => ... -- Allowed by this AI.
 
+    Table : constant array (Character) of Boolean :=
+        (Letter => True, -- Allowed by this AI.
+         others => False);
+
 Every predicate-static expression necessarily has the property that if you plug
 in a static expression in place of every occurrence of the current instance,
 you get a static expression. However, not every expression with this property
@@ -437,26 +443,27 @@
 "Cur_Inst mod 2 = 0" is not, even though both have the above plug-in
 property. The idea is that the set of values for which a predicate-static
 expression is True should be representable as a sequence of static subranges
-whose size is rougly proportional to the size of the relevant source text.  For
+whose size is roughly proportional to the size of the relevant source text.  For
 example:
 
     subtype Even is Natural with
-        Predicate => Cur_Inst mod 2 = 0; -- not predicate-static!
+        Static_Predicate => Cur_Inst mod 2 = 0; -- Illegal!
 
 doesn't qualify, because the the subrange sequence would be
 something like 0..0, 2..2, 4..4, ... 2**31-2..2**31-2, which is
 enormous. We expect implementations to actually form such
 subrange sequences at compile time, which is unreasonable in
 the "mod 2" case. "Cur_Inst > 2", on the other hand, can be
-represented as "3..2**31-1".
+represented as "3..2**31-1". The above would be legal if we
+said Dynamic_Predicate.
 
 Note that the definition of static subtypes allows predicates
 coming from other subtypes:
 
     subtype S1 is Natural with
-        Predicate => S1 < 100 or S1 > 1000;
+        Static_Predicate => S1 < 100 or S1 > 1000;
     subtype S2 is S1 with
-        Predicate => S2 <= 50_000;
+        Static_Predicate => S2 <= 50_000;
 
 S1 is a static subtype, with the subrange sequence 0..99, 1001..Natural'Last.
 S2 is also static, with the subrange sequence 0..99, 1001..50_000.
@@ -479,12 +486,15 @@
 reason is to ensure (without knowing the value of the current instance) that
 predicate-static expressions cannot raise exceptions.
 
-We considered using a different name (perhaps Set_Predicate or
-Static_Predicate) for the static case. We also considered
-using a completely different syntax for the static case -- that's
-essentially the AI05-0153-2 version of this AI).  One problem is that if
-you change a static predicate to a nonstatic one, faraway parts of your
-program can become illegal.  However:
+----------------
+
+An earlier version of this AI proposed a single Predicate aspect, which could
+allow static subtypes or not, depending on whether the expression happened to
+be predicate-static. We decided to split it into two aspects, Static_Predicate
+and Dynamic_Predicate, because otherwise, if you change a static predicate to a
+nonstatic one, faraway parts of your program can become illegal.
+
+The following arguments against the split were rejected:
 
     - They won't change their run-time behavior, just become illegal.
 
@@ -526,8 +536,9 @@
        allow actuals with and without predicates. Without this new syntax,
        actuals would not be allowed to have predicates. We would need to think
        about which language-defined generics should have "Predicate => <>"
-       added. This seems like unnecessary complexity; the Program_Error
-       solution seems sufficient.
+       added. This seems like unnecessary complexity, especially now that
+       Predicate has been split into Static_Predicate and Dynamic_Predicate;
+       the Program_Error solution seems sufficient.
 
     4. The predicate of the actual is ignored in the instance. This seems
        like a bad idea for obvious reasons.
@@ -536,8 +547,8 @@
 
 'for' loops.
 
-We allow "for X in S loop" if S has a user-defined Predicate,
-but only if S is static. It means the same as:
+We allow "for X in S loop" if S has a Static_Predicate,
+but not if it has a Dynamic_Predicate. It means the same as:
 
     for X in S'Base loop
         if X in S then -- query the predicate
@@ -579,7 +590,7 @@
 In some cases, the compiler might unroll the loop.
 For example:
 
-    subtype RGB is Color with Predicate => RGB in Red | Green | Blue;
+    subtype RGB is Color with Static_Predicate => RGB in Red | Green | Blue;
     for X in RGB loop
         Do_Something(X);
     end loop;
@@ -647,7 +658,7 @@
 For example:
 
     type String1 is new String with
-        Predicate => String1'First = 1;
+        Dynamic_Predicate => String1'First = 1;
 
 The compiler can deduce (if the Assertion_Policy is Check) that all objects of
 type String1 have 'First = 1, and optimize accordingly.  It could avoid storing
@@ -658,7 +669,7 @@
    type Rec is record
        A : Natural;
    end record;
-   subtype Decimal_Rec is Rec with Predicate => Rec.A mod 10 = 0;
+   subtype Decimal_Rec is Rec with Dynamic_Predicate => Rec.A mod 10 = 0;
 
    Obj : Decimal_Rec := (A => 10); -- (1)
 
@@ -708,17 +719,17 @@
 Examples:
 
     subtype S is Integer range 1..10 with
-        Predicate => ...;
+        Static_Predicate => ...;
     X: S; -- neither constraint nor predicate is checked
 
-The idea is that X will be initialized later, and the range at
+The idea is that X will be initialized later, and the range and
 predicate will be checked at that time. It makes no sense to
 check the predicate on the declaration of X, since X will have
 some arbitrary junk (possibly invalid) value.
 
     type T is access all String;
     subtype S is T with
-        Predicate => S.all'First = 1;
+        Dynamic_Predicate => S.all'First = 1;
     X: S; -- predicate is not checked
     Y: S := null; -- raises an exception
 
@@ -740,7 +751,7 @@
             Inner: Inner_Record;
         end record;
     subtype S is Outer_Record with
-        Predicate => ...;
+        Dynamic_Predicate => ...;
     X: S; -- predicate IS checked
 
 But if we remove the explicit defaults for A and B,
@@ -781,11 +792,11 @@
 Note that overlapping subsets are allowed in the static case:
 
     subtype S1 is Integer with
-        Predicate => S1 in 1..10;
+        Static_Predicate => S1 in 1..10;
     subtype S2 is Integer with
-        Predicate => S2 in 4..20;
+        Static_Predicate => S2 in 4..20;
     subtype S3 is Integer with
-        Predicate => S3 in S1 | S2; -- overlapping; same as 1..20
+        Static_Predicate => S3 in S1 | S2; -- overlapping; same as 1..20
 
     case ... is
         when S3 => -- OK
@@ -824,9 +835,9 @@
     type Symbol_Ptr is access all Symbol_Record;
 
     subtype Type_Symbol_Ptr is not null Symbol_Ptr with
-       Predicate => Type_Symbol_Ptr.Entity = A_Type;
+       Dynamic_Predicate => Type_Symbol_Ptr.Entity = A_Type;
     subtype Callable_Symbol_Ptr is not null Symbol_Ptr with
-       Predicate =>
+       Dynamic_Predicate =>
           Callable_Symbol_Ptr.Entity = Proc or
           Callable_Symbol_Ptr.Entity = Func or
           Callable_Symbol_Ptr.Entity = An_Entry;
@@ -851,7 +862,8 @@
 size.
 
 Ada measures sizes in bits, but it's sometimes necessary to measure in storage
-units. "Predicate => Blah mod System.Storage_Unit = 0" might come in handy.
+units. "Dynamic_Predicate => Blah mod System.Storage_Unit = 0" might come in
+handy.
 
 A Sort function produces an array (or other sequence) of subtype
 Sorted_Sequence. Binary_Search takes a parameter of that subtype. Very useful
@@ -877,6 +889,565 @@
 
 !appendix
 
+From: Jean-Pierre Rosen
+Sent: Thursday, December 23, 2010  10:01 AM
+
+[Part of a message mostly about the minutes of meeting #42 - Editor]
+
+- From AI05-0153-3(legality rules)
+
+"An index subtype [...] shall not denote a subtype with a
+user-specified predicate."
+The two following paragraphs also refer to user-specified predicate.
+
+This seems to be too narrow. Consider:
+subtype S1 is Integer with Predicate S1 mod 2 = 0; subtype S2 is S1;
+
+Is S2 a subtype with a user specified predicate? Hopefully
+yes, but the formulation is not clear. The definition of a
+predicate of a subtype implies that /part/ of a subtype
+predicate can be user-specified.
+Suggestion:
+"... whose predicate includes parts that are user specified".
+
+****************************************************************
+
+From: Bob Duff
+Sent: Sunday, January 23, 2011  5:25 PM
+
+New version of AI05-0153-3, Subtype predicates. [This is version /02 of
+this AI. - Editor]
+The big change is to split the Predicate aspect in two:
+Static_Predicate and Dynamic_Predicate.
+
+As you all know, I really HATE this "compromise".
+It will certainly enhance Ada's well-deserved reputation for being overly
+complicated!  :-(
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Sunday, January 23, 2011  5:44 PM
+
+> The big change is to split the Predicate aspect in two:
+> Static_Predicate and Dynamic_Predicate.
+>
+> As you all know, I really HATE this "compromise".
+> It will certainly enhance Ada's well-deserved reputation for being
+> overly complicated!  :-(
+
+I dislike it too! GNAT implements this, but under protest :-) and we still have
+the simple Predicate aspect that encompasses both together, and intend to
+maintain that implementation, so in practice I suspect people using GNAT will
+likely use that rather than the split ones.
+
+****************************************************************
+
+From: John Barnes
+Sent: Monday, January 24, 2011  6:24 AM
+
+Having missed the last meeting, I hadn't realised how messy these predicates
+were going. And the dynamic ones sound really dodgy. Why don't we just get rid
+of the dynamic version. Surely the static version is what people will find most
+valueable. This just adds to the feeling that Ada is just as dodgy as other
+languages. Yuk. I feel as if I am going to have to write a rationale that I just
+don't believe in.
+
+PS It is most unlikely that I will get to the Florida meeting. Although
+improved, I am still not fully OK. (I haven't been fully OK for years but I am
+sure you know what I mean!)
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  7:02 AM
+
+I think the dynamic predicates are useful, something like
+
+    subtype X is Integer with
+      Predicate => Is_Prime (X),
+      Default_Value => 1;
+
+makes good sense to me!
+
+****************************************************************
+
+From: John Barnes
+Sent: Monday, January 24, 2011  6:57 AM
+
+Having thought about it over lunch, I am changing my mind.
+
+Since pre and postconditions can call any old stuff and so are as watertight as
+a colander, the subtype predicates might as well be the same. So get rid of the
+static ones.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  7:12 AM
+
+Well you need the special capabilities of static ones, to use them in membership
+tests and case statements. This is the capability that provides non-contiguous
+enumeration types, which to me is *the* most important capability.
+
+   type Colors is (Red, Blue, Yellow, Green, .....)
+
+   subtype RBG is Colors with
+     Predicate => RBG in Red | Blue | Green;
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  7:48 AM
+
+> Having thought about it over lunch, I am changing my mind.
+
+Hey, I see your health really IS improving today.  Good!
+I'm glad your fever dreams regarding predicates have vanished.
+
+> Since pre and postconditions can call any old stuff and so are as
+> watertight as a colander, the subtype predicates might as well be the
+> same. So get rid of the static ones.
+
+Since you missed the last meeting, let me clue you in:
+I strongly advocated having a single Predicate aspect, which can be used in case
+statements and the like only if it obeys certain sort-of-staticness rules. [In
+fact, I was already annoyed that we have predicates, invariants, constraints,
+and null exclusions, all of which are the same thing -- as everybody would see
+if I could get them to remove their Language Lawyer Hats for just a moment!
+Language Lawyer Blindfolds?]
+
+Others were nervous about the colander-like aspects of this aspect.  Giving the
+colander-like ones a different name (Dynamic_Predicate) was a compromise to make
+those people less nervous.  Tucker bullied me incessantly during the meeting,
+until I finally agreed to it.  ;-)
+
+Although Static_Predicate is the more useful of the two, I'm firmly convinced
+that the dynamic ones are necessary. Everybody agrees that we want
+non-contiguous enums. But as soon as you have that, you will certainly want to
+constrain discriminants of that enum type in the same way.
+
+Please don't worry about "dodginess".  Nobody is forcing, or even encouraging,
+anyone to write dodgy predicates.  Just don't do that.
+
+I can give you plenty of non-dodgy examples for your Rat, by the way.
+
+****************************************************************
+
+From: John Barnes
+Sent: Monday, January 24, 2011  7:52 AM
+
+Why can't the one predicate do both?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  8:17 AM
+
+> Why can't the one predicate do both?   John
+
+Because that will cause Randy and others to "snap", and we won't have this
+extremely useful feature at all.
+
+To understand that point of view, consider this analogy:
+Why can't we have a single feature that does what type conversions do, and also
+does what Unchecked_Conversions do? Well, because one is more dangerous, so it's
+a good idea to have separate syntax.
+
+Consider C:  some casts are extremely dangerous, and others are relatively
+innocuous, and it's hard to tell which is which by reading the code.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 24, 2011  8:17 AM
+
+> New version of AI05-0153-3, Subtype predicates.
+> The big change is to split the Predicate aspect in two:
+> Static_Predicate and Dynamic_Predicate.
+>
+> As you all know, I really HATE this "compromise".
+> It will certainly enhance Ada's well-deserved reputation for being
+> overly complicated!  :-( ...
+
+There was a tremendous amount of discussion which led up to this compromise.
+Unfortunately, reopening such discussions can waste a lot of time, unless there
+is some new information.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  8:29 AM
+
+> There was a tremendous amount of discussion which led up to this
+> compromise.  Unfortunately, reopening such discussions can waste a lot
+> of time, unless there is some new information.
+
+I'm not reopening anything.  I'm just venting my frustration.
 
+John wasn't present for those discussions, so I've tried to bring him up to
+speed.  As far as I'm concerned, the issue is settled.
+
+But I'm not like Robert, who thinks that if lots of smart people believe the
+wrong thing, it must therefore be the right thing.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  8:21 AM
+
+By the way, if I had to choose just one AI for Ada 2012, with all the others
+rejected, subtype predicates would be the one.  It's that useful.
+
+And that usefulness comes from its generality.  It's simply impossible to plug
+all the holes in the colander without severely damaging the feature.  Plugging
+just some holes is pointless.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 24, 2011  8:25 AM
+
+> Why can't the one predicate do both? John
+
+The issue here is maintenance.  With just one aspect, a small change can
+dramatically affect where the subtype can be used, and that might not be
+detected until much later.  If the code where the predicate is specified is
+compiled at one time, and the code where the subtype is used is compiled much
+later, by a different developer, then it could be very painful.
+
 ****************************************************************
 
+From: Bob Duff
+Sent: Monday, January 24, 2011  8:31 AM
+
+An obviously-bogus argument, as I explained at the meeting, and also in the AI.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 24, 2011  8:27 AM
+
+> Because that will cause Randy and others to "snap", and we won't have
+> this extremely useful feature at all.
+
+I think maintenance issues were underlying Randy's concern, as I mentioned in my
+prior response.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  9:00 AM
+
+But don't worry too much, in the forseeable future only GNAT will implement Ada 2012 and there you will have one predicate that does both :-)
+
+> Because that will cause Randy and others to "snap", and we won't have
+> this extremely useful feature at all.
+
+And of course it will be just fine to have coding standards forbidding the use
+of the Predicate aspect in GNAT.
+
+P.S. should we have a restriction
+
+No_Implementation_Aspects
+
+Seems like we should, I think I will implement that in GNAT in any case.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  9:01 AM
+
+> By the way, if I had to choose just one AI for Ada 2012, with all the
+> others rejected, subtype predicates would be the one.  It's that
+> useful.
+>
+> And that usefulness comes from its generality.  It's simply impossible
+> to plug all the holes in the colander without severely damaging the
+> feature.  Plugging just some holes is pointless.
+
+I fully agree!
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  9:05 AM
+
+> I think maintenance issues were underlying Randy's concern, as I
+> mentioned in my prior response.
+
+Right, the argument is something like
+
+static predicates: good, easy to maintain, useful etc.
+
+dynamic predicates: bad, hard to maintain, potentially expensive etc.
+
+But if you separate them into two aspects, then I can easily have coding
+standards forbidding or limiting the bad, without affecting the good.
+
+A perfectly reasonable argument, not one I ultimately agree with, but I am happy
+with the AI the way it is separating these, given that I can still implement the
+more general Predicate aspect encompassing them both in GNAT, and furthermore
+this extension does not create problems for those who agree with the argument
+above.
+
+If you find Dynamic_Predicate dangerous and want to restrict its use, then you
+just do the same with Predicate.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  9:07 AM
+
+> But I'm not like Robert, who thinks that if lots of smart people
+> believe the wrong thing, it must therefore be the right thing.
+
+That's not quite the robert philosophy, which goes like this
+
+If you believe that X is correct, but the majority overrules you in a smart
+group of people like the ARG then either
+
+a) you are wrong, and X is not correct
+
+b) you are right, but you are incompetent at presenting your argument
+   sufficiently convincingly.
+
+:-) :-)
+
+In either case, no point in holding on to the minority view point :-)
+
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  9:52 AM
+
+> P.S. should we have a restriction
+>
+> No_Implementation_Aspects
+
+Yes, good idea.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  10:02 AM
+
+By the way, obviously some folks would like to forbid Dynamic_Predicate, so there should be a restriction for that.  Instead of doing it piecemeal, we should do like we did for No_Dependence, and have a general feature for forbidding any aspect.  Somethin
g like:
+
+    pragma Restrictions (No_Aspect => Dynamic_Predicate);
+
+We could have an enum type somewhere that lists all the aspect names.  Or we
+could just allow an "aspect_identifier" there, without involving visibility --
+like pragma arguments.  For aspects that are also attributes or pragmas, the
+restriction should forbid both forms.
+
+I've got no problem with self-imposed or project-imposed restrictions!  If,
+someday, some customer requests No_Evil_Predicates, I expect AdaCore would
+implement it (if we can come up with a coherent definition of "evil").
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 24, 2011  10:19 AM
+
+Or perhaps something like:
+
+   pragma Restrictions(No_Aspect_Specification => Dynamic_Predicate);
+
+to be analogous to "No_Dependence => ...".
+
+****************************************************************
+
+From: Bob Duff
+Sent: Monday, January 24, 2011  10:38 AM
+
+Yes, that's better.  For those aspects that are also attributes, you probably
+want to restrict the specification, but not the query.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, January 24, 2011  9:29 PM
+
+> Because that will cause Randy and others to "snap", and we won't have
+> this extremely useful feature at all.
+>
+> To understand that point of view, consider this analogy:
+> Why can't we have a single feature that does what type conversions do,
+> and also does what Unchecked_Conversions do?
+> Well, because one is more dangerous, so it's a good idea to have
+> separate syntax.
+>
+> Consider C:  some casts are extremely dangerous, and others are
+> relatively innocuous, and it's hard to tell which is which by reading
+> the code.
+
+I hope it doesn't cause me to "snap" (although you never know... :-).
+
+At the risk of prelonging a discussion that is almost over, let me explain my
+position a bit.
+
+A static predicate, to me, is really a kind of constraint. (I would have
+preferred that it be treated that way, but no need to go there.) In particular,
+all of the properties that scalar constraints have also hold for static
+predicates. That means that, once checked, such a predicate holds for an object
+until it is assigned again. (And presumably, the assignment check will again
+check it, so it will still be in range.) That means that they can be included in
+reasoning about the semantics of a particular object. In addition, you can use
+them the same ways in case statements and loops.
+
+OTOH, a dynamic predicate is really a kind of Assert pragma (automatically
+inserted). Like all assert pragmas, the predicate can only be assumed true at
+the point at which it is checked. (And, unlike an assert pragma, it's harder to
+figure out where those points are.) That means that you have to be very careful
+when including these in reasoning about your program. Moreover, even predicates
+that "look" like they hold for the life of an object might not for composite
+objects (as they are not checked when individual components are changed).
+
+I wouldn't want to claim that dynamic predicates aren't useful, just that they
+need a different approach when thinking about the effect on program semantics.
+And that need is best handled by some sort of differentiation between the two,
+especially for the human readers that need to do program reasoning (which is
+most of them).
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Tuesday, January 25, 2011  12:38 AM
+
+> And that need is best handled by some sort of differentiation between
+> the two, especially for the human readers that need to do program
+> reasoning (which is most of them).
+            ^^^^^^^^^^^^^^^^^^^^^^^
+Alas, wishful thinking!
+(sorry, couldn't resist)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, January 25, 2011  12:49 AM
+
+[Specific wording comments here, no political discussion.]
+
+Bob Duff writes:
+...
+> The expression of a Static_Predicate clause shall be
+> "predicate-static"; that is, one of the following:
+>
+>     - a static expression that does not raise any exception;
+>
+>     - a membership test whose left-hand side is the current instance,
+>       and whose right-hand side is static; ???Does that allow "S in
+> (Foo | Bar | Baz)"?
+
+No, because the above isn't syntactally correct :-) (no parens needed). And
+still no even with the parens removed; the right-hand side here is not an
+expression at all, but just a list of choices. It can't be static by itself. You
+probably want to borrow the 4.9(13) wording for memberships:
+
+...and whose membership_choice_list consists only of membership_choices each of which is either a static choice_expression, a static range, or a subtype_mark that denotes range is a static range or whose subtype_mark denotes a static [(scalar or string)] 
subtype;
+
+Probably there is some way to simplify this, but I'll leave that as an exercise
+for the author.
+
+> NOTE: A predicate is not necessarily True for all objects of the
+> subtype at all times. Predicates are checked as specified above, but
+> can become False at other times. For example, the predicate of a
+> record is not checked when a component is modified. Similarly to
+> constraints, predicates can be False for uninitialized variables and
+> other invalid values.
+
+I would have thought that this note would only apply to Dynamic_Predicates. The
+only time it could apply for Static_Predicates is for uninitialized values, and
+that doesn't seem to be worth a note -- it's inclusion in the note mainly seems
+to be to somehow justify making the bogus claim that these are not different in
+how they work. And I don't think it is possible for an non-erroneous program to
+have a Static_Predicate become False for an object for which it previously was
+True. So most of the note seems to imply that Static_Predicates are no better
+than their dynamic brethren, which is baloney. (The last sentence is fine, of
+course I would think it would be a good idea for the *real* difference between
+the kinds of predicates to be explained here, otherwise it might be too
+mysterious. Perhaps something like:
+
+NOTE: A Dynamic_Predicate is not necessarily True for all objects of the subtype
+at all times. Dynamic_Predicates are checked as specified above, but can become
+False at other times. For example, the predicate of a record is not checked when
+a component is modified. In contrast, in the absence of erroneous execution or
+uninitialized variables and other invalid values, a Static_Predicate (like a
+constraint) will remain True all of the time.
+
+[Sorry, didn't realize that there was a political note in the wording when I put
+the "no political discussions" banner at the top.]
+
+...
+> Modify 4.9.1(4/3), so "statically compatible" takes predicates into
+> account:
+>
+>   A constraint is statically compatible with a scalar subtype if it statically
+>   matches the constraint of the subtype, or if both are static and the
+>   constraint is compatible with the subtype.  A constraint is statically
+>   compatible with an access or composite subtype if it statically matches the
+>   constraint of the subtype, or if the subtype is unconstrained.  One subtype
+>   is statically compatible with a second subtype if the constraint of the first
+>   is statically compatible with the second subtype, and in the case of an
+>   access type, if the second subtype excludes null, then so does the first.
+>   {Also, if either subtype has a user-defined predicate, then the first is
+>   statically compatible with the second only if both subtypes are static, and
+>   every value that obeys the predicate of the first obeys the predicate of the
+>   second.}
+>???Is that reasonable to implement?
+
+Since the subtypes are static, this is just a set comparison, and the sets are
+static. So that shouldn't be a problem. It should be possible to turn any
+Static_Predicate (including those with comparison and boolean operators) into a
+set representation, and then a simple compare should give the answer. If you
+couldn't convert to a set, you couldn't test case completeness, so I think it
+has to be doable and you'll have to do it for case statements even if we didn't
+require it here (so doing so here won't add any cost).
+
+> !discussion
+>
+> ???Much of this discussion probably belongs in the AARM!
+
+Well, since AI authors are supposed to propose AARM notes, we know who should
+have done that. :-) I'd certainly appreciate it if you did suggest the notes
+that you think are necessary (and where they should go).
+
+> ----------------
+>
+> An earlier version of this AI proposed a single Predicate aspect,
+> which could allow static subtypes or not, depending on whether the
+> expression happened to be predicate-static. We decided to split it
+> into two aspects, Static_Predicate and Dynamic_Predicate, because
+> otherwise, if you change a static predicate to a nonstatic one,
+> faraway parts of your program can become illegal.
+>
+> The following arguments against the split were rejected:
+>
+>     - They won't change their run-time behavior, just become illegal.
+>
+>     - Changing the VALUES can have the same effect, so different
+>       syntax doesn't really solve the problem.  (E.g. "Cur_Inst
+>       in 1..10" changed to "Cur_Inst in 1..10 | 20".)
+>
+>     - We already have this "problem" for other static things
+>       (changing "subtype S is Integer range 1..10" to
+>       "1..Non_Static" or "1..11" can cause faraway
+>       illegalities).
+>
+>     - Although it might be mildly useful, we don't say
+>       "C: static constant Integer := ...", so why should we
+>       do so for predicates?
+
+It would be nice to say more in *favor* of the split as well; the text seems (to
+me at least) to be biased against the solution we chose. I realize that it is
+asking a lot of you to provide those arguments, as you don't believe in them.
+I'll help you do it if needed.
+
+****************************************************************
+
+From: Robert Dewar
+Sent: Monday, January 24, 2011  9:07 AM
+
+****************************************************************

Questions? Ask the ACAA Technical Agent