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

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

--- ai05s/ai05-0153-1.txt	2010/02/23 07:31:06	1.5
+++ ai05s/ai05-0153-1.txt	2010/02/25 05:01:43	1.6
@@ -73,7 +73,7 @@
 be depended upon. Note that this isn't the same as being allowed to check
 the predicate anywhere at all; there has to be some use of a value or object
 that has the subtype. That's necessary so that it is possible to write
-the predicate without an evaluation of itself being triggered. 
+the predicate without an evaluation of itself being triggered.
 
 Add to the end of 3.3.1(18/2) (which describes the meaning of "initialized
 by default"):
@@ -91,9 +91,9 @@
 derived type. The new (sub)type is considered to have a predicate (even if none
 is explicitly given).
 
-AARM Reason: If a subprogram has parameter(s) whose subtype(s) have 
-defined predicate(s), the generated code of subprogram body may depend on
-those predicates being checked. (A compile could assume that they had been
+AARM Reason: If a subprogram has parameter(s) whose subtype(s) have
+defined predicate(s), the generated code of the subprogram body may depend on
+those predicates being checked. (A compiler could assume that they had been
 checked at the point of a call.) If the predicates did not compose, a call
 of the derived subprogram might not actually check the predicates, and that
 would cause big trouble.
@@ -152,7 +152,7 @@
 
 The tested type is scalar, and the value of the simple_expression belongs
 to the given range, or the range of the named subtype {and
-any predicate of the named subtype evaluates to True}; or 
+any predicate of the named subtype evaluates to True}; or
 
 AARM Ramification: If S has a predicate, S'First in S may evaluate to False.
 Similarly for S'Last.
@@ -211,14 +211,14 @@
 
 The model here is that a predicate has *no* effect on the static or dynamic
 semantics of a constraint. That is, if a predicate is applied to an indefinite
-type, the resulting subtype is indefinite. If a predicate is applies to an
+type, the resulting subtype is indefinite. If a predicate is applied to an
 unconstrained subtype, the resulting subtype is unconstrained. And so on.
 
 This mirrors the semantics of null exclusions (which also are not constraints).
 
-Note that this can lead to some unusual circumstances:
+Note that this could have lead to some unusual circumstances:
 
-     subtype Even is Integer range 1 .. 10 when Predicate => Even mod 2 = 0;
+     subtype Even is Integer range 1 .. 10 with Predicate => Even mod 2 = 0;
      type Evens is array (Even) of Boolean; -- 5 or 10 elements?
      Obj : Evens;
      Obj(1) := False; -- Would Raise Predicate_Error.
@@ -248,7 +248,7 @@
 (2) A predicate does not clearly define 'First or 'Last values, so calling
 it a constraint on a scalar subtype brings up many nasty questions. For
 instance,
-     subtype Mapping is Integer range 1 .. 10 when Predicate => Map(Mapping);
+     subtype Mapping is Integer range 1 .. 10 with Predicate => Map(Mapping);
 What is Even'First? Without analyzing the body of Map (which may not even have
 been written yet), we can't say. And even if we made it dynamic, Map may
 have side effects and not return the same answer each time it is called.
@@ -259,7 +259,7 @@
 
 These problems can be worked around by adding various restrictions, but that
 just makes predicates less useful and far more complex.
-     
+
 ---
 
 We define predicates to be part of static matching, so that subtypes with
@@ -336,8 +336,8 @@
     function Type_Size (A_Type : Type_Symbol_Ptr) return Size_Type;
 
     procedure Generate_Call_Parameters (Callee : Callable_Symbol_Ptr; ...);
+
 
- 
 Now, a call to Type_Size or Generate_Call_Parameters with a pointer to the wrong
 kind of symbol record will be detected at the call site rather than at some later
 point. The call site is closer to the source of the error; in addition, it is
@@ -2166,5 +2166,510 @@
 Date: Tuesday, June 23, 2009  8:32 AM
 
 Right.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, February 24, 2010  3:29 PM
+
+I like this AI a lot.
+
+My homework assignment says "Examples for AI05-0153-1 (subtype predicates)".
+I don't understand what I'm supposed to do, because this AI already has a nice example.
+
+So instead I'm commenting on some details.
+
+> !standard  3.2.2(2)                                   10-02-11    AI05-0153-1/04
+...
+> The actual predicate is the given expression anded with the predicate
+> (if any) of the parent subtype. (The predicate of any subtype that
+> does not have one can be assumed to be the boolean literal True.)
+
+Parent subtype doesn't mean what you want it to mean:
+
+8.d/2     To be honest: {AI95-00442-01} Any name of a category of types (such
+          as "discrete", "real", or "limited") is also used to qualify its
+          subtypes, as well as its objects, values, declarations, and
+          definitions, such as an "integer type declaration" or an "integer
+          value." In addition, if a term such as "parent subtype" or "index
+          subtype" is defined, then the corresponding term for the type of the
+          subtype is "parent type" or "index type."
+
+3/2   {AI95-00251-01} {AI95-00401-01} {AI95-00419-01} {parent subtype}
+{parent type} The parent_subtype_indication defines the parent subtype; its type
+is the parent type. The interface_list defines the progenitor types (see 3.9.4).
+A derived type has one parent type and zero or more progenitor types.
+
+...
+> [Editor's note: We allow Program_Error because all bounded errors can
+> raise Program_Error.
+
+There is one exception to that, which I'm too lazy to look up right now.
+I think it's related to controlled types.
+
+I don't see any value to the user in allowing more than one exception.
+
+>... The "proceeds normally" wording is the same as 4.8(11.1/2).]
+>
+> AARM Ramification: An implementation can evaluate a predicate any time
+> an object is accessed in any way, if it desires. We have to say this
+> so that any side-effects of the predicate (bad practice, but surely
+> allowed) cannot be depended upon. Note that this isn't the same as
+> being allowed to check the predicate anywhere at all; there has to be
+> some use of a value or object that has the subtype. That's necessary
+> so that it is possible to write the predicate without an evaluation of itself being triggered.
+
+I don't understand that last sentence.
+
+But I agree we can't allow "anywhere at all" -- that would mean the compiler
+could insert race conditions at will, and other bad things.
+
+My understanding is that implementations are REQUIRED to check predicates in
+many cases, such as parameter passing (because that depends on subtype
+conversion).  Is that correct?  It might be easier to understand if we said that
+first, because otherwise my first impression is "this feature is totally
+optional".
+
+> Add to the end of 3.3.1(18/2) (which describes the meaning of
+> "initialized by default"):
+>
+> If the nominal subtype has a predicate, the predicate is applied to
+> the object and Assertions.Predicate_Error is raised if the result is False.
+>
+> [Editor's note: We need to check that default initialized objects
+> don't violate their predicate.]
+
+I don't think I agree with this.  At least not in all cases.
+E.g., for integers:
+
+    X : T; -- (1)
+    ...
+    if Flag then
+        X := 123;
+    end if;
+    ...
+    if Flag then
+        X := X + 1;
+    end if;
+
+I don't think I want the possibly-invalid value checked at (1).
+
+> Modify 3.4(18-22/2):
+>
+> Informally, the predicate of the corresponding subtype is that of the
+> subtype of the parent/progenitor type anded with the predicate of the
+> derived type. The new (sub)type is considered to have a predicate
+> (even if none is explicitly given).
+>
+> AARM Reason: If a subprogram has parameter(s) whose subtype(s) have
+> defined predicate(s), the generated code of subprogram body may depend
+> on
+                                             ^
+                                             the
+
+> those predicates being checked. (A compile could assume that they had
+> been
+                                     compileR
+
+> checked at the point of a call.) If the predicates did not compose, a
+> call of the derived subprogram might not actually check the
+> predicates, and that would cause big trouble.
+>
+> Add as the last sentence of 3.6(9):
+>
+> An index subtype shall not statically denote a subtype with a predicate.
+
+"statically denote"?  Why "statically"?  Why not just "be"?
+
+> checked at the point of a call.) If the predicates did not compose, a
+> call of the derived subprogram might not actually check the
+> predicates, and that would cause big trouble.
+>
+> Add as the last sentence of 3.6(9):
+>
+> An index subtype shall not statically denote a subtype with a predicate.
+
+"statically denote"?  Why "statically"?  Why not just "be"?
+
+> Add as the last sentence of 3.6(21):
+>
+> The elaboration of an array_type_definition raises Program_Error if
+> the index subtype has a predicate.
+>
+> AARM Reason: We don't want to create "holey" array types; it is very
+> confusing as to whether the values for which the predicate returns
+> False have associated elements. By raising Program_Error, we prevent
+> generic contract problems. But we also have a legality rule so when it
+> is statically known (outside of a generic) we detect the problem at
+> compile-time.]
+
+Ah, I see.
+
+This is inconsistent with similar cases, where we just make it a run time error, and trust compilers to give warnings when statically known.
+
+> Add after 3.6.1(5):
+>
+> The discrete_range of an index_constraint shall not statically denote
+> a subtype with a predicate.
+>
+> Add as the last sentence of 3.6.1(8):
+>
+> The elaboration of an index_constraint raises Program_Error if any
+> discrete_range is a subtype with a predicate.
+>
+> AARM Reason: We don't want to create "holey" array subtypes. By
+> raising Program_Error, we prevent generic contract problems. But we
+> also have a legality rule so when it is statically known (outside of a
+> generic) we detect the problem at compile-time.]
+
+You don't need to repeat this.  Just refer to the earlier comment.
+
+> Add after 4.1.2(4):
+>
+> Legality Rules
+>
+> The discrete_range of a slice shall not statically denote a subtype
+> with a predicate.
+>
+> Add as the last sentence of 4.1.2(7):
+>
+> The evaluation of a slice raises Program_Error if any discrete_range
+> is a subtype with a predicate.
+>
+> AARM Reason: We don't want to create "holey" slices, especially as
+> slices can be required to be passed by reference (for by-reference
+> component types), and ignoring the predicate would be very confusing.
+> By raising Program_Error, we prevent generic contract problems. But we
+> also have a legality rule so when it is statically known (outside of a
+> generic) we detect the problem at compile-time.]
+
+Same here.
+
+...
+> Add after 4.6(58):
+>
+> Implementation Permissions
+>
+> If the target subtype of a conversion has a predicate, and the nominal
+> subtype of the operand is that same subtype, an implementation may
+> omit the application of a predicate to the operand.
+
+We might need to define "same subtype".  Or use "statically matching"?
+
+...
+> !discussion
+>
+> This proposal seems similar to type invariants on the surface.
+> However, these two constructs solve different problems. ...
+
+I think this philosophical discussion is rubbish, but so long as we can agree on
+the language rules (we're very close!), we don't need to hash that out.
+
+>...A type invariant is a
+> requirement on all values of a type outside of the type's defining
+>package(s). In particular, it does not vary depending on the view of
+>an object. A constraint and/or predicate is a requirement on a
+>particular  view of an object. It can be different on different views
+>of the same object  (as in a formal parameter). Thus it can be used to
+>specify temporary or  transient requirements on an object.
+>
+> ---
+>
+> The model here is that a predicate has *no* effect on the static or
+> dynamic semantics of a constraint. That is, if a predicate is applied
+> to an indefinite type, the resulting subtype is indefinite. If a
+> predicate is applies to an
+                                                               applieD
+
+> unconstrained subtype, the resulting subtype is unconstrained. And so on.
+>
+> This mirrors the semantics of null exclusions (which also are not constraints).
+
+...for reasons only language lawyers can grok.  Sigh.
+
+> Note that this can lead to some unusual circumstances:
+>
+>      subtype Even is Integer range 1 .. 10 when Predicate => Even mod
+> 2 = 0;
+                                             WITH
+
+>      type Evens is array (Even) of Boolean; -- 5 or 10 elements?
+
+But you outlawed this above.  Maybe you're trying to explain why, but the
+wording says "can", not "could (if it were legal)" and so forth.
+
+>      Obj : Evens;
+>      Obj(1) := False; -- Would Raise Predicate_Error.
+>
+> Type Evens has length 10. Evens'range goes from 1 .. 10. However,
+> attempting to index component 1 will raise Predicate_Error. (That's
+> because 1 will be converted to subtype Even, as noted in 4.1.1(7), and
+> that will trigger a predicate check.) However, the situation gets
+> nastier still when arrays are sliced by subtypes with a
+> predicate:
+>
+>     Str : String := "1234567890";
+>
+>     Put(Str(Even));
+>
+> One might expect to have "24680" printed, but since the constraints
+> are unchanged, "1234567890" would actually be printed. Because of this
+> weird behavior, we do not allow predicates on index subtypes. In order
+> to avoid breaking the contract model, we raise Program_Error in generic bodies if the subtype has a predicate.
+
+Here's a radical notion: Raise P_E when an instance is elaborated, if it
+contains any such evil things, even in unreachable/unreached code.
+
+> ---
+>
+> Originally, this proposal made predicates "user-defined constraints".
+> This does not work, however, for a number of reasons:
+
+Bah!  We can call them whatever we like, it doesn't make any difference to the
+rules.
+
+...
+> For example:
+>
+>    type Rec is record
+>        A : Natural;
+>    end record;
+>    subtype Decimal_Rec is Rec with Predicate => Rec.A mod 10 = 0;
+>
+>    Obj : Decimal_Rec := (A => 10); -- (1)
+>
+>    procedure Do_It (P : in out Rec) is
+>    begin
+>        P.A := 5;
+>    end Do_It;
+>
+>    Do_It (Obj); -- (2)
+>    Put (Obj in Decimal_Rec); -- (3)
+>
+> The predicate on Decimal_Rec will be checked on the aggregate at (1).
+> However, after the call at (2), the predicate is no longer true for Obj.
+> The call at (3) will print False. Implementations are allowed to check
+
+So why don't we require a predicate check on the way out?
+That's the one common case where subtype conversion doesn't cover it.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, February 24, 2010  8:15 PM
+
+...
+> My homework assignment says "Examples for AI05-0153-1 (subtype
+> predicates)".
+> I don't understand what I'm supposed to do, because this AI already
+> has a nice example.
+
+My recollection is that you said something to the effect that you had "many
+examples" of how this would help. Steve said that he wanted to see some of them.
+Thus you got an action item.
+
+Essentially, the one example doesn't seem to have been enough to sway others. If
+you want to keep this AI alive, I think you need to find some additional
+examples of usage. (In e-mail, you've typically used variations of this
+particular compiler example that I used in the original AI; I guess the feeling
+is that not enough Ada users are writing compilers to matter.)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, February 24, 2010  8:52 PM
+
+...
+> > The actual predicate is the given expression anded with the
+> > predicate (if any) of the parent subtype. (The predicate of any
+> > subtype that does not have one can be assumed to be the boolean
+> > literal True.)
+>
+> Parent subtype doesn't mean what you want it to mean:
+...
+
+OK, but at this point, you have to propose wording that *does* mean the right
+thing. Nothing at all comes to mind.
+
+...
+> > [Editor's note: We allow Program_Error because all bounded errors
+> > can raise Program_Error.
+>
+> There is one exception to that, which I'm too lazy to look up right now.
+> I think it's related to controlled types.
+
+If there is, it would violate 1.1.5(8): "...but in any case one possible effect
+of a bounded error is the raising of the exception Program_Error.".
+
+> I don't see any value to the user in allowing more than one exception.
+
+I'm not going to try to ignore 1.1.5(8); it would allow raising Program_Error
+even if we didn't say that.
+
+...
+> > AARM Ramification: An implementation can evaluate a predicate any
+> > time an object is accessed in any way, if it desires. We have to say
+> > this so that any side-effects of the predicate (bad practice, but
+> > surely
+> > allowed) cannot be depended upon. Note that this isn't the same as
+> > being allowed to check the predicate anywhere at all; there has to
+> > be some use of a value or object that has the subtype. That's
+> > necessary so that it is possible to write the predicate without an
+> > evaluation of itself being triggered.
+>
+> I don't understand that last sentence.
+
+If we allowed evaluation of the predicate *anywhere*, that would include during
+the evaluation of the predicate. Which wouldn't work very well. :-) I can
+imagine implementations that might do that. Beyond that, there is the tasking
+issues of evaluating these anywhere; I didn't want to talk about those
+specifically because its hard to define what shouldn't be allowed.
+
+If you can word this better, suggest away.
+
+> But I agree we can't allow "anywhere at all" -- that would mean the
+> compiler could insert race conditions at will, and other bad things.
+>
+> My understanding is that implementations are REQUIRED to check
+> predicates in many cases, such as parameter passing (because that
+> depends on subtype conversion).  Is that correct?  It might be easier
+> to understand if we said that first, because otherwise my first
+> impression is "this feature is totally optional".
+
+The requirement to write wording in RM order often leads to non-optimal orders.
+In this case, though, I simply have no idea where this text belongs. I suggested
+perhaps in 13.9.1, which would avoid the problem as it would be buried in the
+back of the RM.
+
+> > Add to the end of 3.3.1(18/2) (which describes the meaning of
+> > "initialized by default"):
+> >
+> > If the nominal subtype has a predicate, the predicate is applied to
+> > the object and Assertions.Predicate_Error is raised if the
+> result is False.
+> >
+> > [Editor's note: We need to check that default initialized objects
+> > don't violate their predicate.]
+>
+> I don't think I agree with this.  At least not in all cases.
+> E.g., for integers:
+>
+>     X : T; -- (1)
+>     ...
+>     if Flag then
+>         X := 123;
+>     end if;
+>     ...
+>     if Flag then
+>         X := X + 1;
+>     end if;
+>
+> I don't think I want the possibly-invalid value checked at (1).
+
+That's not the case I was thinking of. I was thinking of a record type:
+
+    type Foo with Predicate (B*2 = C) is record
+        B : Natural := 10;
+        C : Natural := 15;
+    end record
+
+    X : Foo; -- Violates the predicate.
+
+In this case, there is no reason to ever check this (given the permission to
+skip checks when the subtype doesn't change). So it would never be required to
+be detected, which is nasty.
+
+...
+> > AARM Reason: We don't want to create "holey" array types; it is very
+> > confusing as to whether the values for which the predicate returns
+> > False have associated elements. By raising Program_Error, we prevent
+> > generic contract problems. But we also have a legality rule so when
+> > it is statically known (outside of a generic) we detect the problem
+> > at compile-time.]
+>
+> Ah, I see.
+>
+> This is inconsistent with similar cases, where we just make it a run
+> time error, and trust compilers to give warnings when statically
+> known.
+
+It's consistent with accessibility checks. In most other cases, we've made the
+body cases always illegal. I don't know of any cases where we make such things
+runtime errors.
+
+> > Add after 3.6.1(5):
+> >
+> > The discrete_range of an index_constraint shall not
+> statically denote
+> > a subtype with a predicate.
+> >
+> > Add as the last sentence of 3.6.1(8):
+> >
+> > The elaboration of an index_constraint raises Program_Error if any
+> > discrete_range is a subtype with a predicate.
+> >
+> > AARM Reason: We don't want to create "holey" array subtypes. By
+> > raising Program_Error, we prevent generic contract problems. But we
+> > also have a legality rule so when it is statically known
+> (outside of a
+> > generic) we detect the problem at compile-time.]
+>
+> You don't need to repeat this.  Just refer to the earlier comment.
+
+Yes I do, it's in a different clause, and I want the RM to be reasonable useful as a reference. This particular case is iffy, but the others (like the 4.1.2) are much more valuable - no one reading 4.1.2 is going to go read 3.6 to figure out why the rules
 are the way they are.
+
+> > This proposal seems similar to type invariants on the surface.
+> > However, these two constructs solve different problems. ...
+>
+> I think this philosophical discussion is rubbish, but so long as we
+> can agree on the language rules (we're very close!), we don't need to
+> hash that out.
+
+Well, if you disagree with this, then you are saying that you don't want both
+AI-146 and AI-153-1. And in that case, it's this AI that is likely to disappear.
+So we need to be able to explain the difference, or prepare to drop one.
+
+
+> >      subtype Even is Integer range 1 .. 10 when Predicate
+> => Even mod
+> > 2 = 0;
+>                                              WITH
+>
+> >      type Evens is array (Even) of Boolean; -- 5 or 10 elements?
+>
+> But you outlawed this above.  Maybe you're trying to explain why, but
+> the wording says "can", not "could (if it were legal)" and so forth.
+
+It wasn't illegal when this was written, and the rewrite was very simple and
+quick, as this AI was left on life-support.
+
+...
+> > Originally, this proposal made predicates "user-defined constraints".
+> > This does not work, however, for a number of reasons:
+>
+> Bah!  We can call them whatever we like, it doesn't make any
+> difference to the rules.
+
+Only if you are willing to abandon the current model of constraints in the
+language. I don't know of anyone (other than you, perhaps) that's willing to do
+that.
+
+...
+> > The predicate on Decimal_Rec will be checked on the aggregate at (1).
+> > However, after the call at (2), the predicate is no longer true for Obj.
+> > The call at (3) will print False. Implementations are allowed to
+> > check
+>
+> So why don't we require a predicate check on the way out?
+> That's the one common case where subtype conversion doesn't cover it.
+
+Don't copy-backs use subtype conversion? (At least for by-copy types). For
+by-reference types, it would be a completely new check in a place where none
+currently exists. That seems bad, at least for this feature (which was designed
+to be minimum cost).
+
+Anyway, you've done a pretty good job of reminding me why, while I'd like some
+way to do this, it really doesn't work very well. I'm probably going to vote to
+kill this in the absense of new examples of use.
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent