CVS difference for ai05s/ai05-0153-1.txt
--- ai05s/ai05-0153-1.txt 2012/02/19 04:48:04 1.14
+++ ai05s/ai05-0153-1.txt 2012/04/05 06:28:27 1.15
@@ -9061,5 +9061,3572 @@
****************************************************************
+From: Robert Dewar
+Date: Thursday, October 7, 2010 3:05 PM
+I see the point, makes sense, let's eliminate this oddity.
+
+P.S. when discussions get down to this level, one senses some convergence in
+agreement on the main ideas, which is good, since I am right now implementing
+them. But it's only a preview, we can always change our minds later :-)
+
+****************************************************************
+
+From: Steve Baird
+Date: Thursday, October 7, 2010 2:59 PM
+
+Is it intended that imposing a static predicate on a static subtype results in
+another static subtype ?
+
+For example:
+
+ subtype S1 is Integer with (S1 in 1 .. 10) or (S1 = -1);
+
+ Named_Number constant := Boolean'Pos (123 in S1); -- legal?
+
+I think we want this.
+
+Given
+
+ subtype Truth is Boolean range True .. True;
+
+ subtype S2 is Integer with predicate
+ (S2 = 0) or Truth'(S2 not in -10 .. 10)
+
+would the following be rejected
+
+ X : constant := Boolean'Pos (0 in S2);
+
+due to 4.9's
+
+ For a static expression that is evaluated:
+ The expression is illegal if its evaluation fails a language-defined
+ check other than Overflow_Check.
+?
+
+I see no definitional problems with this - I just wanted to be clear about the
+consequences of allowing exception-raising static predicates.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 7, 2010 3:08 PM
+
+> Is it intended that imposing a static predicate on a static subtype
+> results in another static subtype ?
+>
+> For example:
+>
+> subtype S1 is Integer with (S1 in 1 .. 10) or (S1 = -1);
+>
+> Named_Number constant := Boolean'Pos (123 in S1); -- legal?
+>
+> I think we want this.
+
+Seems reasonable ...
+
+> I see no definitional problems with this - I just wanted to be clear
+> about the consequences of allowing exception-raising static predicates.
+
+Ugly, let's not allow qualification, as suggested by Tuck, why introduce the
+complexity of exception-raising static predicates for a language feature of no
+conceivable use, which would be there just for unnecessary consistency reasons
+:-)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 7, 2010 3:17 PM
+
+> A useful property of membership, comparison, logical ops, and
+> parentheses, is that there is no possibility for failure.
+> Allowing a qualified expression to be applied to an expression
+> involving the subtype name (current instance) would introduce the
+> possibility of raising an exception, which definitely adds unnecessary
+> complexity. I think we should limit ourselves to never-failing
+> operations for the parts which are non-static expressions, namely the
+> operations having the subtype current instance as an operand or
+> sub-operand.
+
+That was actually my intent - it was why I added "static subtype" to my
+description. Qualification is usually used for disambiguation, and there is no
+intent to raise an exception. It's not possible for Boolean'(<some expr allowed
+by these rules>) to raise an exception, for instance.
+
+So perhaps the rule ought to be "qualified expressions where the expression is
+allowed by these rules and the named subtype is static and has the base range of
+its type". Or alternatively: "qualified expressions where the expression is
+allowed by these rules and the named subtype is static and no subtype check can
+fail" (this would allow Natural'(X) if X is a subtype of Natural).
+
+But I do feel pretty strongly that if we are allowing parenthesized expressions
+that we should also be allowing qualified expressions that also don't raise
+exceptions. Otherwise, we risk a situation where it's hard to eliminate a
+resolution problem from a predicate (because doing so makes the predicate
+non-static -- that's the maintenance objection that I've had to this particular
+concept from the beginning).
+
+****************************************************************
+
+From: Tucker Taft
+Date: Thursday, October 7, 2010 3:38 PM
+
+> But I do feel pretty strongly that if we are allowing parenthesized
+> expressions that we should also be allowing qualified expressions that
+> also don't raise exceptions. Otherwise, we risk a situation where it's
+> hard to eliminate a resolution problem from a predicate (because doing
+> so makes the predicate non-static -- that's the maintenance objection
+> that I've had to this particular concept from the beginning).
+
+I have trouble imagining how this could happen. Since you will be able to apply
+a qualified expression to all of the static operands, and the subtype name is
+not overloadable, why would you need to apply it to the result as well? We
+aren't allowing user-defined operators to be called, since they wouldn't be
+static. How can we get into a situation where you need to qualify the result?
+
+If we do feel the need, I would go with allowing qualification by unconstrained
+subtypes and constrained scalar subtypes whose range is the base range. But I
+have real trouble imagining the need...
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 7, 2010 4:42 PM
+
+...
+> How can we get into a situation where you need to qualify the result?
+
+I was imagining that there exists a user-defined boolean type:
+
+ package My_Bool_Pack is
+ type My_Bool is new Standard.Boolean;
+
+ function "and" (Left, Right : My_Bool) return My_Bool;
+ ... other operators here ...
+ end My_Bool_Pack;
+
+ with My_Bool_Pack;
+ package Another_Pack is
+ type An_Int is range ...;
+ function "=" (Left, Right : An_Int) return My_Bool_Pack.My_Bool;
+ -- Remember, the "Boolean" versions are declared here automatically.
+ end Another_Pack;
+
+ with My_Bool_Pack, Another_Pack; use My_Bool_Pack, Another_Pack;
+ procedure Try_It is
+ subtype Foo is An_Int with predicate => Foo /= 10 and Foo /= 20; -- !!
+ begin
+ ...
+
+In this case, the only way to ensure that Standard.Boolean is used is to qualify
+it (the expression is ambiguous as written); qualifying the operands doesn't
+help. And the result is static if and only if it is qualified as Boolean
+(My_Bool would definitely not be static).
+
+I'm not going to claim this is common, but I could imagine it happening (the key
+seems to be the overloading on another boolean type). It just seems wrong to say
+that if someone did this elsewhere in your system, you can't define a static set
+subtype. (I also suspect that there are more likely ways to cause this problem,
+this was just the first way that came to mind.)
+
+> If we do feel the need, I would go with allowing qualification by
+> unconstrained subtypes and constrained scalar subtypes whose range is
+> the base range.
+> But I have real trouble imagining the need...
+
+I don't think this is the sort of thing that is going to happen very often.
+But one of the important points of Ada is programming in large, where there is
+always a way to workaround whatever bizarreness you've inherited from some other
+subsystem. I think it would be wrong to not have some way to get a static set
+subtype.
+
+This doesn't concern me anywhere near as much as the fact that if we *don't*
+allow qualification here,
+
+ subtype Foo is An_Int
+ with predicate => Boolean'(Foo /= 10) and Foo /= 20;
+
+would not be a static predicate, but there isn't any indication at the
+declaration point that this intent failed. Instead, you'll get an error far away
+when you try to use it in a case statement or loop. And the reason that this
+isn't static surely isn't obvious!
+
+With the error handling system in Janus/Ada, the error message will be cryptic
+at best (we don't have a way to refer to things declared outside of the current
+unit). I presume GNAT will do better, but it still looks as if it will be at
+least partly mysterious.
+
+That's why I wanted an indication at the point of the declaration that this was
+intended to be a static subtype. After all, this seems very similar to the
+situation with overriding (where whatever you declare will be legal, but it
+might not do what you want or cause problems in far-away code). We ended up
+inventing overriding indicators to reduce the problems with that. I don't want
+to repeat that with this feature.
+
+Anyway, a mitigation of this problem is to allow more sorts of predicate
+expressions to be static. That makes it less likely that that maintenance or
+just structuring will cause the predicate to be non-static when the programmer
+intended it to be static. (It's impossible to reduce this possibility to zero,
+of course, so my concern will always exist.)
+
+I had suggested marking these with a separate aspect name, but that doesn't seem
+to fly. I don't have any other good ideas as to how to mark the programmers
+intentions here (a pragma is *not* a good idea, sorry), but I'm still convinced
+that is necessary.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 7, 2010 4:50 PM
+
+> If we do feel the need, I would go with allowing qualification by
+> unconstrained subtypes and constrained scalar subtypes whose range is
+> the base range.
+> But I have real trouble imagining the need...
+
+But the need must be based on a realistic example, not some abstract notion of
+being able to add junk qualifications without causing maintenance problems.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 7, 2010 4:55 PM
+
+> But I do feel pretty strongly that if we are allowing parenthesized
+> expressions that we should also be allowing qualified expressions that
+> also don't raise exceptions. Otherwise, we risk a situation where it's
+> hard to eliminate a resolution problem from a predicate (because doing
+> so makes the predicate non-static -- that's the maintenance objection
+> that I've had to this particular concept from the beginning).
+
+I see the (minor) point here, but blowing this up into a serious maintenance
+problem sees really overdrawn. I am willing to bet that if an implementation
+fails to allow qualified expressions here, the bug will never be noticed except
+by an over-enthusastic ACATS test.
+
+That being said, I have no problem with any of the possible resolutions of this
+issue, since I don't think it matters at all, and any of the possibilities is
+trivial to implement :-)
+
+For now, I will allow qualifications :-)
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Date: Monday, October 11, 2010 8:26 AM
+
+> I had suggested marking these with a separate aspect name, but that
+> doesn't seem to fly. I don't have any other good ideas as to how to
+> mark the programmers intentions here (a pragma is *not* a good idea,
+> sorry), but I'm still convinced that is necessary.
+
+Inventing new syntax is such fun! What about:
+
+with predicate => [constant] <expression>; or
+with predicate => constant'(<expression>);
+
+Note that there are certainly other places where the ability to specify that an
+expression is expected to be static might be useful.
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 9:05 AM
+
+> > I had suggested marking these with a separate aspect name, but that
+> > doesn't seem to fly. I don't have any other good ideas as to how to
+> > mark the programmers intentions here (a pragma is *not* a good idea,
+> > sorry), but I'm still convinced that is necessary.
+
+For what it's worth, if you want to say, "I'd like to place a restriction on
+myself (or on my team), dear compiler please complain (at compile time if
+possible) if I violate that restriction", a pragma is the perfect tool.
+
+This is one of those "good taste" pragmas that can be removed or ignored without
+causing any trouble.
+
+I don't think it's worth the trouble, but I have no objection if some compiler
+wants to implement such a pragma, and if it gets heavily used, we can
+standardize in 2015 or 2099 or whenever.
+
+> Inventing new syntax is such fun! What about:
+>
+> with predicate => [constant] <expression>; or with predicate =>
+> constant'(<expression>);
+>
+> Note that there are certainly other places where the ability to
+> specify that an expression is expected to be static might be useful.
+
+Well, I'd prefer not to add to the confusion between "constant" and "static".
+
+****************************************************************
+
+From: Robert Dewar
+Date: Monday, October 11, 2010 4:48 PM
+
+> Inventing new syntax is such fun! What about:
+>
+> with predicate => [constant]<expression>; or with predicate =>
+> constant'(<expression>);
+>
+> Note that there are certainly other places where the ability to
+> specify that an expression is expected to be static might be useful.
+
+I really find the confusion this would cause between constant and static
+horrible. I further find it unnecessary to have any syntax here.
+
+As I have said before, we already have
+
+ X : constant Integer := complicated expression;
+
+and in some remote package
+
+ case B is
+
+ ...
+ when X => ...
+
+legal? Depends on whether complicated expression meets the (very complex and
+non-intuitive IMO) rules in 4.9.
+
+So what's the big deal about
+
+ subtype X is Integer with
+ predicate X = complicated expression;
+
+and we use the subtype name in a case
+
+The situation to me is identical. If the second upsets you, then the first one
+should upset you equally.
+
+That's why a pragma is a nice solution, because you can't fix the first case
+with syntax here, but you could have a pragma that fixed it
+
+ pragma Static (local_NAME);
+
+if name is a constant object, checks its value is static
+
+if name is a subtype, checks its bounds are static, and if it has a predicate,
+that the predicate is static.
+
+I don't think we should add such a pragma to the definition right now, but it
+seems a reasonable thing for an implementation to add (we are planning to add
+this in GNAT).
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 5:36 PM
+
+> I don't think we should add such a pragma to the definition right now,
+> but it seems a reasonable thing for an implementation to add (we are
+> planning to add this in GNAT).
+
+I don't see the point of such a pragma. Sure, changing from static to nonstatic
+can cause faraway errors. But changing the VALUE of a static expression can
+cause faraway errors, too. Same for changing the range (or predicate!) of a
+static subtype.
+
+If somebody says "when X =>" in a case statement, then changing X to nonstatic
+is no more likely to cause trouble than changing the value (or range, or static
+predicate) of X!
+
+Basically, if you change the visible part of a package, you can affect clients.
+If you don't like that, then use deferred constants, private types, etc.
+
+P.S. Don't forget that these faraway errors are a GOOD thing. It's what the
+full-coverage/no-overlap rules are all about.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 8, 2010 4:58 PM
+
+> The whole idea of static predicates is a new one and not really
+> related to the existing proposal (it's much more related to set
+> constraints than predicates).
+
+FWIW, I disagree with that assessment (from a technical point of view).
+
+>... The only reason we didn't approve AI05-0153-1 in Valencia was that
+>we didn't agree on the wording for the new restrictions on composite
+>predicate expressions. So I would prefer to have the existing AI
+>reflect the decisions of that meeting exactly; and have a separate
+>alternative with the more complex proposal that is now being crafted
+>here. That way, we can see if it really is more complex or not.
+
+Well, the restrictions imposed in Valencia are a radical departure from what I
+originally wrote. If anything, THAT version of the AI should be split out as a
+separate proposal.
+
+There's nothing in the minutes that gives any hint as to why these restrictions
+were approved. At first I thought they were an attempt to make sure that
+predicates are (like constraints) always true for all valid values of the
+subtype. But those restrictions don't even come close to ensuring that, and
+"valid" is meaningless for composites, so I ended up thinking, "What were they
+thinking?!".
+
+It was only recently that I read the Valencia minutes, and I was surprised to
+find that Tucker has an action item for ai05-0153. I thought it was my
+responsibility.
+
+I am about to send a new version of ai05-0153, which (1) fixes bugs in
+ai05-0153-1, and (2) incorporates the functionality from ai05-0153-2. I've read
+all the emails in those two AI's, plus a whole bunch that came in since emails
+were filed.
+
+I'd prefer my new version be a new version of ai05-0153-1, but call it -3 or -4
+if you insist. (With the nonexistent Valencia proposal being -4 or -3. Do we
+really need this proliferation of alternatives?!)
+
+For the record, I am strongly opposed to any proposal that doesn't allow
+function calls -- the subprogram is the most important abstraction facility
+invented in the history of computer science!
+
+> There is no significant extra work involved in this, given that all
+> I'm asking is to keep the Valencia proposal around intact.
+
+There is no Valencia proposal, other than in the minutes!
+In any case, all old versions of all AI's are kept in CVS.
+
+Please read my new proposal before commenting on this rant. ;-)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Saturday, October 9, 2010 12:23 AM
+
+(You asked me to read your proposal before commenting, but since the questions
+in this message are procedural, and about the technical content of the Valencia
+meeting, I don't quite know why. Nor do I have time to do that now; quite
+possibly I won't read it until right before the meeting. So I answered these
+now.)
+
+...
+> > The whole idea of static predicates is a new one and not really
+> > related to the existing proposal (it's much more related to set
+> > constraints than predicates).
+>
+> FWIW, I disagree with that assessment (from a technical point of view).
+
+I'd like to know why (without reading a 77K document and trying to guess from
+that). But let's discuss that off-line; I don't want to have to record the
+ensuing discussion and it isn't likely to be relevant to the alternative
+proposal.
+
+> >... The only reason we didn't approve AI05-0153-1 in Valencia was
+> >that we didn't agree on the wording for the new restrictions on
+> >composite predicate expressions. So I would prefer to have the
+> >existing AI reflect the decisions of that meeting exactly; and have
+> >a separate alternative with the more complex proposal that is now
+> >being crafted here. That way, we can see if it really is more complex or not.
+>
+> Well, the restrictions imposed in Valencia are a radical departure
+> from what I originally wrote. If anything, THAT version of the AI
+> should be split out as a separate proposal.
+
+Sorry, but this originally was my idea, and I wrote the first couple versions of
+this AI. It later got assigned to you, and you surely did work on it, but you
+have no claim of originality.
+
+But that's irrelevant in any case. I want this alternative to reflect what the
+ARG decided, not what Bob Duff by himself wants. That's no more relevant that
+what any other individual ARG members want.
+
+> There's nothing in the minutes that gives any hint as to why these
+> restrictions were approved. At first I thought they were an attempt
+> to make sure that predicates are (like
+> constraints) always true for all valid values of the subtype.
+> But those restrictions don't even come close to ensuring that, and
+> "valid" is meaningless for composites, so I ended up thinking, "What
+> were they thinking?!".
+
+Yes, that is exactly what we were thinking: it's an attempt to ensure that
+predicates don't become False for composite values (so that they work more like
+constraints). Essentially, if the predicate check succeeds for a composite
+value, it will continue to succeed until the entire value is changed.
+
+But I don't understand why you say they don't come close to accomplishing that.
+It is possible with these restrictions to build a predicate that depends on
+global state that changes, and that would cause trouble. But I can't imagine
+anyone thinking that would be a good idea in any case. It is *not* possible with
+these restrictions to build a predicate that depends on any part of the
+composite value other than the bounds and discriminants, so there is no
+possibility of a component change making the predicate turn False.
+
+Note that there was a lot of discomfort with the idea that predicates don't hold
+for composites except at the instant of checking. These rules were an attempt to
+deal with that discomfort. It did not appear that the proposal was going to
+reach a consensus without some attempt to deal with this problem (if you have
+*not* dealt with this problem, your proposal is already on shaky ground).
+
+I suspect that we have much more support for static scalar predicates (which are
+really set constraints with a different syntax :-) than we do for the dynamic
+composite predicates. So this whole proposal might be in trouble. OTOH, people
+may have changed their minds since Valencia. Or maybe there is some other way to
+make this work. You were not at the meeting, and I can't record everything that
+is said (or record the looks on people's faces, etc.), so I realize that you are
+surely missing some of the nuances (and maybe the entire idea if I did a lousy
+job of explaining it in the minutes). But let me say that I think your previous
+positions on this proposal are pretty much at the fringe of the net ARG
+position, and a consensus is likely to require a more moderate position.
+
+> It was only recently that I read the Valencia minutes, and I was
+> surprised to find that Tucker has an action item for ai05-0153.
+> I thought it was my responsibility.
+
+I don't know why. We're trying to finish these AIs, and when they are done, I
+usually get them to make the final editorial revisions. In this case, we
+believed that AI05-0153-1 was finished except for a paragraph of wording to be
+provided by Tucker. One solitary paragraph. So it was assigned to Tucker for
+that paragraph, and then I was going to make the other minor changes.
+
+Now, I agree that subsequent discussion has changed that assumption of it being
+finished, but of course that doesn't retroactively change the work assignments!
+
+Keep in mind that we assigned you two other critical AIs in part because we
+didn't think you had any other homework. By not figuring out what you were
+supposed to be working on, you've doubled your workload (or potentially delayed
+the completion of the Amendment). So please read the minutes next time!
+
+> I'd prefer my new version be a new version of ai05-0153-1, but call it
+> -3 or -4 if you insist. (With the nonexistent Valencia proposal being
+> -4 or -3. Do we really need this proliferation of alternatives?!)
+
+The Valencia proposal will be -1, and yours will be -3. We surely don't need any
+other version, because those versions were discussed and considered not
+acceptable in meetings. What would the point be? But we surely need to keep a
+version with some attempt to make them more like constraints -- a number of
+members deemed this important.
+
+...
+> > There is no significant extra work involved in this, given that all
+> > I'm asking is to keep the Valencia proposal around intact.
+>
+> There is no Valencia proposal, other than in the minutes!
+> In any case, all old versions of all AI's are kept in CVS.
+
+Where else would it be? People in this group are notorious for doing their
+homework at the last minute. There surely will be a proposal, because I'll get
+wording from Tucker (or do it myself) and then update the AI.
+
+I consider this very important because it is an attempt (maybe not one that will
+work out) to address a concern that has prevented a number of members from
+supporting the predicate proposal. Even if it ultimately is rejected, we need to
+keep track of the attempt. And, as you are noting, there is not yet any proposal
+in the CVS -- so that has to be done. And I'm not going to try to somehow do it
+on top of your new proposal, that way lies madness (mine, at least). Thus, it is
+better to make your unrequested proposal a separate alternative (even if it more
+nearly reflects the thinking of the recent e-mail threads).
+
+****************************************************************
+
+From: Bob Duff
+Date: Saturday, October 9, 2010 11:32 AM
+
+> > FWIW, I disagree with that assessment (from a technical point of view).
+>
+> I'd like to know why (without reading a 77K document and trying to
+> guess from that). But let's discuss that off-line; I don't want to
+> have to record the ensuing discussion and it isn't likely to be
+> relevant to the alternative proposal.
+
+I don't think there's anything to discuss. I've stated my opinion. You're the
+editor, and you plan to overrule me. Nothing wrong with that, and nothing
+further to discuss.
+
+> > Well, the restrictions imposed in Valencia are a radical departure
+> > from what I originally wrote. If anything, THAT version of the AI
+> > should be split out as a separate proposal.
+>
+> Sorry, but this originally was my idea, ...
+
+Heh? I certainly didn't intend to imply any originality!
+In fact, I don't think I put ANYTHING original in this AI -- I got it all from
+the existing AI versions, and the emails, from you and many others.
+
+My "what I originally wrote" above is simply a reference to version 6 of the AI
+(that is, AI05-0153-1/06, dated 10-05-19), which I wrote, based heavily on your
+previous work.
+
+I realize that your version was an attempt to show what a stupid idea "general
+predicate expressions" is. Nothing wrong with that, but I obviously disagree
+with the conclusion. The Valencia restrictions are a radical departure, in the
+sense that it's no longer "general".
+
+>...and I wrote the first couple
+> versions of this AI. It later got assigned to you, and you surely did
+>work on it, but you have no claim of originality.
+
+Right, I have no claim of originality.
+
+> But that's irrelevant in any case. I want this alternative to reflect
+> what the ARG decided, not what Bob Duff by himself wants. That's no
+> more relevant that what any other individual ARG members want.
+>
+> > There's nothing in the minutes that gives any hint as to why these
+> > restrictions were approved. At first I thought they were an attempt
+> > to make sure that predicates are (like
+> > constraints) always true for all valid values of the subtype.
+> > But those restrictions don't even come close to ensuring that, and
+> > "valid" is meaningless for composites, so I ended up thinking, "What
+> > were they thinking?!".
+>
+> Yes, that is exactly what we were thinking: it's an attempt to ensure
+> that predicates don't become False for composite values (so that they
+> work more like constraints).
+
+OK, I think I see. The ARG is understandably nervous about the fact that
+predicates can surprisingly become false. ARG attempted to pass some laws
+fixing that, but failed, and then passed those laws anyway.
+
+Note that predicates can surprisingly become false for scalars, too, and access
+types, so it's not clear to me why the nervousness is focused on composites.
+
+>...Essentially, if the predicate check succeeds for a composite value,
+>it will continue to succeed until the entire value is changed.
+
+That's false, as you note below (global variables!).
+
+> But I don't understand why you say they don't come close to
+> accomplishing that. It is possible with these restrictions to build a
+> predicate that depends on global state that changes, and that would cause
+> trouble.
+
+Right, that's why. Forbidding refs to components, while allowing refs to
+globals doesn't accomplish the goal.
+
+Also, "Predicate => Is_Good(Cur_Inst)" can depend on components.
+It's not clear to me whether that was intended to be forbidden in Valencia.
+
+>... But I
+> can't imagine anyone thinking that would be a good idea in any case.
+
+But it makes no sense to say "we need rules to prevent X", and then turn around
+and say "we don't really need to prevent X, because nobody would think it's a
+good idea to do X".
+
+Either you trust programmers to write sensible predicates, or you FORCE
+programmers to write sensible predicates -- no middle ground can make sense.
+
+So... You're sucking me into a technical discussion without having read my new
+proposal, which I was hoping to avoid. I think I'd better wrap this up, until
+you and others have had a chance to read it. I know it's long -- sorry about
+that!
+
+> OTOH, people may have changed their minds since Valencia. Or maybe
+> there is some other way to make this work. You were not at the
+> meeting, and I can't record everything that is said (or record the
+> looks on people's faces, etc.), so I realize that you are surely
+> missing some of the nuances (and maybe the entire idea if I did a lousy job of
+> explaining it in the minutes).
+
+I'm NOT saying you did a lousy job! Your note-taking skills are far superior to
+mine, for what that's worth. (I never took notes in school, other than to write
+down the homework assignment. I can't seem to pay attention to what's being said
+if I also try to write it down.)
+
+But the fact remains that I can't understand exactly what restrictions were
+approved at Valencia. All I can say is I'm strongly opposed to having
+restrictions that attempt to forbid Bad Things if the restrictions don't
+actually prevent those Bad Things. Any restrictions that allow Steve's favorite
+example ("subtype T is ... with Predicate => T > Calendar.Clock") are misguided.
+
+> But let me say that I think your previous positions on this proposal
+> are pretty much at the fringe of the net ARG position, and a consensus
+> is likely to require a more moderate position.
+
+I tried to produce a more moderate position, but in recent days, people (Robert,
+Ed, Tucker, you, perhaps others) have been pushing for more and more
+functionality (more cases when predicates are considered static, more allowed
+uses of static ones ('for' loops), so I put all that in).
+
+> > It was only recently that I read the Valencia minutes, and I was
+> > surprised to find that Tucker has an action item for ai05-0153.
+> > I thought it was my responsibility.
+>
+> I don't know why. We're trying to finish these AIs, and when they are
+> done, I usually get them to make the final editorial revisions. In
+> this case, we believed that AI05-0153-1 was finished except for a
+> paragraph of wording to be provided by Tucker. One solitary paragraph.
+> So it was assigned to Tucker for that paragraph, and then I was going to make the other minor changes.
+
+Surely that paragraph requires some rationale -- a statement of what the
+restrictions try to prevent, along with an argument that they do, in fact,
+prevent such things.
+
+> Now, I agree that subsequent discussion has changed that assumption of
+> it being finished, but of course that doesn't retroactively change the
+> work assignments!
+>
+> Keep in mind that we assigned you two other critical AIs in part
+> because we didn't think you had any other homework. By not figuring
+> out what you were supposed to be working on, you've doubled your
+> workload (or potentially delayed the completion of the Amendment). So
+> please read the minutes next time!
+
+Consider me suitably admonished.
+
+I plan to do the rest of my ARG homework next week, unless some AdaCore
+customers cause emergencies I need to deal with.
+
+> The Valencia proposal will be -1, and yours will be -3.
+
+You're the editor -- it's your decision.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Saturday, October 9, 2010 12:00 PM
+
+For me, the only really important parts of the predicate proposal are for scalar
+types (both static and dynamic predicates are useful), and for composites, only
+restrictions on the set of possible discriminants seem useful.
+
+I don't mind them supporting more general stuff, providing the attempt at
+generality does not compromise what to me are the useful uses :-)
+
+BTW, here is the current general implementation of static predicates in the GNAT
+Ada 2012 preview edition. Note that GNAT now only allows loops over static
+predicates, so the fact that this program compiles means it recognized all
+predicates as static. The loops sure are useful for testing purposes :-)
+
+Test program:
+
+> with Text_IO; use Text_IO;
+> procedure Predicate_Loops is
+> type Int is range 1 .. 10;
+>
+> subtype P1 is Int with
+> predicate =>
+> P1 in 3 | 5 .. 7 | 10 | 5 .. 6 | 6;
+>
+> subtype P2 is Int with
+> predicate => P2 > 6;
+>
+> subtype P3 is Int with
+> predicate => ((P3 > 6) and P3 < 9);
+>
+> subtype P4 is Int with
+> predicate => (P4 in P2) and P4 < 10;
+>
+> subtype P5 is Int with
+> predicate => P5 < 3 or P5 > 8;
+>
+> subtype P6 is P5 with
+> predicate => P6 /= 1 and P6 /= 10;
+>
+> subtype P7 is Int with
+> predicate => Boolean'(P7 not in 1 .. 7);
+>
+> subtype P8 is Int with
+> predicate => not (P8 = 3 or else P8 in 5 .. 10);
+>
+> subtype P9 is Int with
+> predicate => P9 in 1 .. 8 xor P9 in 3 .. 10;
+>
+> type Enum is (A,B,C,D,E,F,G,H,I,J);
+>
+> subtype E1 is Enum with
+> predicate =>
+> E1 in C | E .. G | J | E .. F | F;
+>
+> subtype E2 is Enum with
+> predicate => E2 > F;
+>
+> subtype E3 is Enum with
+> predicate => ((E3 > F) and E3 < I);
+>
+> subtype E4 is Enum with
+> predicate => (E4 in E2) and E4 < J;
+>
+> subtype E5 is Enum with
+> predicate => E5 < C or E5 > H;
+>
+> subtype E6 is E5 with
+> predicate => E6 /= A and E6 /= J;
+>
+> subtype E7 is Enum with
+> predicate => Boolean'(E7 not in A .. G);
+>
+> subtype E8 is Enum with
+> predicate => not (E8 = C or else E8 in E .. J);
+>
+> subtype E9 is Enum with
+> predicate => E9 in A .. H xor E9 in C .. J;
+>
+> subtype T1 is Int with
+> predicate => True;
+>
+> subtype T2 is Int with
+> predicate => False;
+>
+> subtype T3 is Enum with
+> predicate => True;
+>
+> subtype T4 is Enum with
+> predicate => False;
+>
+>
+> begin
+> for J in P1 loop
+> Put_Line ("P1:" & J'Img);
+> end loop;
+>
+> for J in P2 loop
+> Put_Line ("P2:" & J'Img);
+> end loop;
+>
+> for J in P3 loop
+> Put_Line ("P3:" & J'Img);
+> end loop;
+>
+> for J in P4 loop
+> Put_Line ("P4:" & J'Img);
+> end loop;
+>
+> for J in P5 loop
+> Put_Line ("P5:" & J'Img);
+> end loop;
+>
+> for J in P6 loop
+> Put_Line ("P6:" & J'Img);
+> end loop;
+>
+> for J in P7 loop
+> Put_Line ("P7:" & J'Img);
+> end loop;
+>
+> for J in P8 loop
+> Put_Line ("P8:" & J'Img);
+> end loop;
+>
+> for J in P9 loop
+> Put_Line ("P9:" & J'Img);
+> end loop;
+>
+> for J in E1 loop
+> Put_Line ("E1:" & J'Img);
+> end loop;
+>
+> for J in E2 loop
+> Put_Line ("E2:" & J'Img);
+> end loop;
+>
+> for J in E3 loop
+> Put_Line ("E3:" & J'Img);
+> end loop;
+>
+> for J in E4 loop
+> Put_Line ("E4:" & J'Img);
+> end loop;
+>
+> for J in E5 loop
+> Put_Line ("E5:" & J'Img);
+> end loop;
+>
+> for J in E6 loop
+> Put_Line ("E6:" & J'Img);
+> end loop;
+>
+> for J in E7 loop
+> Put_Line ("E7:" & J'Img);
+> end loop;
+>
+> for J in E8 loop
+> Put_Line ("E8:" & J'Img);
+> end loop;
+>
+> for J in E9 loop
+> Put_Line ("E9:" & J'Img);
+> end loop;
+>
+> for J in T1 loop
+> Put_Line ("T1:" & J'Img);
+> end loop;
+>
+> for J in T2 loop
+> Put_Line ("T2:" & J'Img);
+> end loop;
+>
+> for J in T3 loop
+> Put_Line ("T3:" & J'Img);
+> end loop;
+>
+> for J in T4 loop
+> Put_Line ("T4:" & J'Img);
+> end loop;
+>
+> end Predicate_Loops;
+
+Output:
+
+> P1: 3
+> P1: 5
+> P1: 6
+> P1: 7
+> P1: 10
+> P2: 7
+> P2: 8
+> P2: 9
+> P2: 10
+> P3: 7
+> P3: 8
+> P4: 7
+> P4: 8
+> P4: 9
+> P5: 1
+> P5: 2
+> P5: 9
+> P5: 10
+> P6: 2
+> P6: 9
+> P7: 8
+> P7: 9
+> P7: 10
+> P8: 1
+> P8: 2
+> P8: 4
+> P9: 1
+> P9: 2
+> P9: 9
+> P9: 10
+> E1:C
+> E1:E
+> E1:F
+> E1:G
+> E1:J
+> E2:G
+> E2:H
+> E2:I
+> E2:J
+> E3:G
+> E3:H
+> E4:G
+> E4:H
+> E4:I
+> E5:A
+> E5:B
+> E5:I
+> E5:J
+> E6:B
+> E6:I
+> E7:H
+> E7:I
+> E7:J
+> E8:A
+> E8:B
+> E8:D
+> E9:A
+> E9:B
+> E9:I
+> E9:J
+> T1: 1
+> T1: 2
+> T1: 3
+> T1: 4
+> T1: 5
+> T1: 6
+> T1: 7
+> T1: 8
+> T1: 9
+> T1: 10
+> T3:A
+> T3:B
+> T3:C
+> T3:D
+> T3:E
+> T3:F
+> T3:G
+> T3:H
+> T3:I
+> T3:J
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Sunday, October 10, 2010 10:19 PM
+
+(I'm going to engage in some meta-technical discussion, but I'm going to try to avoid talking about a specific proposal, to avoid "sucking" Bob into a
+discussion...)
+
+Bob Duff writes:
+...
+> >...Essentially, if the predicate check succeeds for a composite
+> >value, it will continue to succeed until the entire value is changed.
+>
+> That's false, as you note below (global variables!).
+
+I don't think we care about global variables. (More below.)
+
+> > But I don't understand why you say they don't come close to
+> > accomplishing that. It is possible with these restrictions to build
+> > a predicate that depends on global state that changes, and
+> that would cause trouble.
+>
+> Right, that's why. Forbidding refs to components, while allowing refs
+> to globals doesn't accomplish the goal.
+>
+> Also, "Predicate => Is_Good(Cur_Inst)" can depend on components.
+> It's not clear to me whether that was intended to be forbidden in
+> Valencia.
+
+My view of the rule (not necessarily the same as what everyone else was thinking; the rule was only partially worded) is that it banned any reference to the current instance other than discriminants and bounds. Thus the above would not be allowed.
+
+> >... But I
+> > can't imagine anyone thinking that would be a good idea in any case.
+>
+> But it makes no sense to say "we need rules to prevent X", and then
+> turn around and say "we don't really need to prevent X, because nobody
+> would think it's a good idea to do X".
+>
+> Either you trust programmers to write sensible predicates, or you
+> FORCE programmers to write sensible predicates -- no middle ground can
+> make sense.
+
+I think you are setting up a straw man here.
+
+It is unlikely that there are any rules (for anything) which can prevent all
+intentional misuse. (For example, the container reference tampering checks won't
+work if someone does an unchecked deallocation of the reference object.) What
+rules can prevent is accidental misuse, and are especially important if there is
+some reason to expect users to want to do something that won't work.
+
+In the case of predicates (in the abstract, not referring to any particular
+proposal), there are a number of things that can be done that "won't work" (i.e.
+cause a change in result of a predicate without a recheck):
+
+(1) Dependence on the current instance of an elementary type (not counting
+ dereference) and dependence on bounds and discriminants of a current
+ instance (or a dereference). Always OK.
+
+(2) Dependence on non-discriminant component values of a current instance (or a
+ dereference). This is a dangerous case, because it is likely to be written
+ either on purpose by a misquided programmer or by accident. And this is
+ exactly the case where the programmer would expect the predicate to either
+ still hold or be rechecked (neither of which is possible for single
+ component assignments).
+
+(3) Dependence on globals that don't change such that the function calls (or
+ direct object references) always return the same value for the same
+ arguments. Memo functions are in this category. Obviously, these don't
+ present any problem, so we don't need to prevent such references.
+
+(4) Dependence on globals that are expected to change frequently. Function calls
+ to Clock and Random are in this category. I can't imagine any useful use for
+ such a predicate; these are clearly pathologies and thus are "intentional
+ misuse". We don't need to try to prevent such cases (if we can, great).
+
+(5) Finally, dependence on globals that change rarely. This category includes
+ program bugs (functions/objects that are supposed to be in category 3 but
+ are broken), but I suppose it might include something done intentionally.
+ These also might be dangerous, but whether this category is important
+ depends on whether you think that much other than bugs will fall into it. In
+ my programs at least, there aren't many globals that would fall into this
+ category (it's a good thing to avoid these whether or not predicates are
+ involved), so the number of non-pathological cases possible would be quite
+ small.
+
+Thus, evaluation of possible rules comes down to two things: how serious you
+think the problem is, and how likely you think category (5) is. It certainly is
+consistent to think that category (5) is a very small set [thinking that most
+globals falling into category (3) or (4)], and thus concentrate only on category
+(2). Moreover, there is a pragmatic issue here: we don't have the tools to
+detect category (5) problems, but that doesn't necessarily mean that we should
+just throw up our hands about the much more common category (2) problems.
+
+Now, if *I* were running the circus (to steal someone's turn of phrase), we'd
+have checked global in/global out annotations, and calling functions or using
+global variables would be prohibited in predicates (and
+preconditions/postconditions/invariants). And then the checking would be pretty
+airtight (and we still could allow function calls in many cases). But we don't
+have that, so we are going to have to settle for a less airtight solution (which
+might be no solution at all).
+
+End of meta-technical discussion...
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 8:53 AM
+
+> (I'm going to engage in some meta-technical discussion, but I'm going
+> to try to avoid talking about a specific proposal, to avoid "sucking"
+> Bob into a
+> discussion...)
+
+I'm puzzled -- you seem to talk pure "technical" below.
+I can't resist getting sucked in. ;-)
+
+> I don't think we care about global variables. (More below.)
+
+Well, my evil twin, who is a rude and sarcastic kind of guy, says:
+
+ I lock my front door when I go out, to keep people from
+ sneaking into my house and stealing my stuff. I keep
+ the back door open, though, because I don't want the
+ hassle of unlocking it when I return.
+
+ In fact, I squirted epoxy glue into the front door keyhole,
+ which prevents even my own legitimate use of the front door,
+ but it sure does prevent burglars from using the front door!
+
+Seriously, this reminds me of the "functions can't have 'inout'
+params, but they can do what they like with globals" idea.
+I even understand that point of view, while disagreeing with it.
+
+> > Also, "Predicate => Is_Good(Cur_Inst)" can depend on components.
+> > It's not clear to me whether that was intended to be forbidden in
+> > Valencia.
+>
+> My view of the rule (not necessarily the same as what everyone else
+> was thinking; the rule was only partially worded) is that it banned
+> any reference to the current instance other than discriminants and
+> bounds. Thus the above would not be allowed.
+
+I've been playing around with the predicate feature in GNAT for the past few
+days, partly to test Robert's work, and partly just for the fun of it. I've
+tried to write "typical" uses of the feature. FWIW, I've written quite a few
+functions of the Is_Good nature above. Some refer to discrims, some to other
+components.
+
+Hence, if this restriction exists, it seems like "glue in the keyhole".
+
+> > Either you trust programmers to write sensible predicates, or you
+> > FORCE programmers to write sensible predicates -- no middle ground
+> > can make sense.
+>
+> I think you are setting up a straw man here.
+
+Not deliberately.
+
+I really want a feature that can express general properties of things.
+I often want to refer to components, I often want to call functions, and I
+sometimes want to refer to globals.
+
+The closer we get to forbidding the "bad" cases, the more "good" cases get
+forbidden. And any in-between position is doubly frustrating: I can't do what I
+want, and I *still* don't get the "predicates always true" assurance.
+
+> It is unlikely that there are any rules (for anything) which can
+> prevent all intentional misuse. (For example, the container reference
+> tampering checks won't work if someone does an unchecked deallocation
+> of the reference object.)
+
+Now THAT part seems like a strawman. We all know that chap-13-ish features mean
+"all bets are off", for predicates or any other proposed feature. So of course
+I understand the "predicates always true" goal as "predicates always true unless
+you use unchechked_blah and the like".
+
+I snipped the rest (but I did read it carefully). Two points:
+
+1. I can think of a few cases where using global vars in predicates
+ is reasonable.
+
+2. I object to the term "dangerous" when referring to predicates
+ that might not ALWAYS be true. These aren't like array bounds checks,
+ where missing one case can trash memory. Nothing particularly
+ bad happens, and the predicate will likely get checked soon -- as
+ soon as you pass the thing as a parameter.
+
+3. The alternative is putting in pragmas Assert. Those are no better;
+ they'll become false sometimes, but eventually (you hope) you'll
+ trip over another Assert. In other words, the predicate feature
+ is useful despite loopholes.
+
+4. Make that three points.
+
+5. Constraints have a giant loophole, too: uninitialized variables.
+ Note that even discriminants can contain uninitialized junk.
+
+> Now, if *I* were running the circus (to steal someone's turn of
+> phrase),
+
+I stole it from Steve, who stole it from Dr. Seuss.
+
+> we'd have checked global in/global out annotations,...
+
+I agree we could do a much better job if we had globals annotations.
+Keep in mind that we might have them someday, either as a language feature, or
+as a proof-tool-specific feature (see SPARK).
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 3:36 PM
+
+In Valencia, one concern was that if you say "X.Comp := ...;", then the
+predicate of X is not checked. The predicate of Comp is, but not the object as
+a whole.
+
+One way to address this would be to say it *is* checked, if the left-hand side
+of an assignment is a selected or indexed component. Also if an actual for an
+[in]out param is such a component.
+
+There would still be loopholes, but plugging this obvious one might make some
+people (including me, I admit!) happier.
+
+I'm not sure it's a good idea, but it's far better than the baby/bathwater ideas
+of Valencia (which of course ALSO imply that no predicate can be checked on
+"X.Comp := ...;", because there can be none!).
+
+****************************************************************
+
+From: Robert Dewar
+Date: Monday, October 11, 2010 4:40 PM
+
+To me it seems horrible to allow predicates to mention components and then not
+check on component assignment. Makes no sense at all.
+
+I am quite happy with a solution that forbids predicates from mentioning
+components, or otherwise restricts things. Really to me the ONLY useful use of
+predicates for composites is in checking discriminants. Otherwise I think
+invariants handle things just fine.
+
+But if this is allowed, it seems obvious to me it should be checked on a
+component assignment.
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 4:47 PM
+
+> To me it seems horrible to allow predicates to mention components and
+> then not check on component assignment.
+> Makes no sense at all.
+
+I tend to write a lot of code where record and array components are "mostly
+constant". They get initialized, and change little or none afterward.
+
+So why don't I make all the components into discriminants?
+Well, discriminants are restricted in various ways so it won't usually work.
+
+Anyway, in this scenario, predicates referencing components makes a lot of sense
+(and checking on assignment into components could perhaps make sense as well).
+
+****************************************************************
+
+From: Robert Dewar
+Date: Monday, October 11, 2010 5:22 PM
+
+That's the thing, IF you allow this, then I think you have to check on
+assignment into components, and this seems a LOT of overhead if you only use the
+predicate to check the discriminants.
+
+Ah, missing language feature (constant components) :-)
+
+****************************************************************
+
+From: Bob Duff
+Date: Monday, October 11, 2010 5:48 PM
+
+> That's the thing, IF you allow this, then I think you have to check on
+> assignment into components, and this seems a LOT of overhead if you
+> only use the predicate to check the discriminants.
+
+Heh?
+
+There's no overhead for checking on assignment into components in my scenario --
+I don't do that (or only rarely).
+
+OK, I suppose this depends on a not-yet-implemented optimization:
+don't check predicates when they depend on things that can't change.
+
+Anyway, I don't care much about efficiency of assertion checks in general --
+there's always the fallback of turning them off.
+
+I say, "If your assertions are efficient enough for production mode, then you
+don't have enough assertions."
+
+> Ah, missing language feature (constant components) :-)
+
+Look at Ada (circa) 1979! There were constant components, which were
+more-or-less like discriminants. Or maybe it was still Green then. ;-)
+
+****************************************************************
+
+From: Robert Dewar
+Date: Tuesday, October 12, 2010 11:29 AM
+
+> OK, I suppose this depends on a not-yet-implemented optimization:
+> don't check predicates when they depend on things that can't change.
+
+HUGELY hard to do, since predicates call bodies that you cannot see, so this has
+to be done at link time!
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, October 12, 2010 11:39 AM
+
+No, no, no. My idea is to optimize at compile time, and only if the relevant
+information is available. E.g. here's my favorite predicate of all (which I wish
+applied to String itself!):
+
+ subtype Good_String is String with
+ Predicate => Good_String'First = 1;
+
+'First can never change.
+
+ procedure P(S: in out Good_String) is
+ begin
+ if S /= "" then
+ S(1) := To_Upper(S(1)); -- (*)
+ end if;
+ end P;
+
+If we require predicate checks on component assignments, the predicate check at
+(*) can be optimized away, because the predicate does not depend on any
+component.
+
+That may or may not be hard, but it doesn't require any link-time work!
+
+If you change "Good_String'First = 1" to "Is_Good(Good_String)", then you don't
+get any optimization (unless perhaps if Is_Good is inlined?).
+
+And as I said, if we don't implement such optimizations, that's OK because I can
+always turn off the checks. Optimizing checks is IMHO merely a "nice to have".
+
+****************************************************************
+
+From: Robert Dewar
+Date: Tuesday, October 12, 2010 11:47 AM
+
+...
+> 'First can never change.
+
+Right, but we are talking here about the composite case with record components,
+most likely such invariants would be written as function calls I would think.
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, October 12, 2010 12:02 PM
+
+Then I'm not sure what your point is.
+
+Efficiency doesn't matter -- only distributed overhead matters.
+
+That is, this sub-discussion is about whether we should restrict predicates on
+composite types as discussed in Valencia. We don't have a precise definition of
+what those restrictions are, but they probably forbid refs to non-discrim
+components (perhaps forbidding function calls).
+
+It makes no sense to say "checks on predicates that refer to non-discrim
+components are inefficient, so we should forbid such predicates".
+
+It MIGHT make sense to say "checks on predicates that refer only to
+bounds/discrims will be slower if we allow more general predicates". This is a
+distributed overhead argument.
+
+Maybe an example would clarify your point.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Tuesday, October 12, 2010 12:21 PM
+
+...
+> It MIGHT make sense to say "checks on predicates that refer only to
+> bounds/discrims will be slower if we allow more general predicates".
+> This is a distributed overhead argument.
+
+Yes, that's my point, if we insist on checking on component assignment, that's
+totally useless in the bounds/discrims case, but will add overhead.
+
+> Maybe an example would clarify your point.
+
+ Predicate => Typ.Discrim = Red;
+
+Now any assignment to a component will check the discriminant which is silly. Of
+course in this case you MAY be able to optimize some cases away, but if the
+tests on the discriminants are hidden in a function you won't be able to!
+
+****************************************************************
+
+From: Bob Duff
+Date: Tuesday, October 12, 2010 7:08 PM
+
+OK, I understand your point now, and it's correct.
+
+However, note that Randy thinks the Valencia proposal forbids such "hiding in a
+function".
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, October 12, 2010 9:37 PM
+
+> > (I'm going to engage in some meta-technical discussion, but I'm
+> > going to try to avoid talking about a specific proposal, to avoid "sucking"
+> > Bob into a
+> > discussion...)
+>
+> I'm puzzled -- you seem to talk pure "technical" below.
+> I can't resist getting sucked in. ;-)
+
+I was trying to avoid any discussion of any particular proposal, and just look
+at the general issues. Even the general issues have some technical content...
+
+...
+> Seriously, this reminds me of the "functions can't have 'inout'
+> params, but they can do what they like with globals" idea.
+> I even understand that point of view, while disagreeing with it.
+
+I personally would prefer to ban access to globals as well. Tucker actually
+suggested something on that line (only allow references to constants), but it
+seemed too holey (there are many constants that aren't really constant, plus we
+couldn't do anything useful about the function case).
+
+...
+> > > Either you trust programmers to write sensible predicates, or you
+> > > FORCE programmers to write sensible predicates -- no middle ground
+> > > can make sense.
+> >
+> > I think you are setting up a straw man here.
+>
+> Not deliberately.
+>
+> I really want a feature that can express general properties of things.
+> I often want to refer to components, I often want to call functions,
+> and I sometimes want to refer to globals.
+>
+> The closer we get to forbidding the "bad" cases, the more "good" cases
+> get forbidden. And any in-between position is doubly frustrating:
+> I can't do what I want, and I *still* don't get the "predicates always
+> true" assurance.
+
+If there was a rule that would in fact be implementable and ensured the
+"predicates are always true", I'd be strongly in favor of it.
+
+But part of the problem is most of what you say you want to do is *exactly* what
+I don't think you ought to be doing (more below). So I'm not surprised there is
+some tension...
+
+...
+> > It is unlikely that there are any rules (for anything) which can
+> > prevent all intentional misuse. (For example, the container
+> > reference tampering checks won't work if someone does an unchecked
+> > deallocation of the reference
+> > object.)
+>
+> Now THAT part seems like a strawman. We all know that chap-13-ish
+> features mean "all bets are off", for predicates or any other proposed
+> feature. So of course I understand the "predicates always true" goal
+> as "predicates always true unless you use unchechked_blah and the
+> like".
+
+I don't agree in the sense that I don't think it is very valuable to treat
+chapter 13 as some sort of second-class citizen. And I suspect that if you asked
+6 Ada lawyers what features were included in this all-bets are off category,
+you'd get 9 answers.
+
+I much prefer to think of this in terms of pathologies. Doing an unchecked
+deallocation of a reference to defeat the protection is a pathology -- no one is
+going to do it by accident or expect it to work. However, doing an
+unchecked_conversion to get the representation of an enumeration value is not a
+pathology, and saying that "all bets are off" just because there is a safe
+occurrence of Unchecked_Conversion around does not seem helpful. And the same is
+true for address clauses and AtoA and a lot of other chapter 13 things.
+
+In this case, I'm certain that calling a random number generator in a predicate
+is a pathology. Only Ada lawyers would think to do so, and it has no possible
+use. I don't see this case as different than abusing Unchecked_Conversion.
+
+> I snipped the rest (but I did read it carefully). Two points:
+>
+> 1. I can think of a few cases where using global vars in predicates
+> is reasonable.
+
+Please give one or more examples. I cannot think of any such cases, and some
+compelling examples would be a big help in moving the discussion along.
+
+> 2. I object to the term "dangerous" when referring to predicates
+> that might not ALWAYS be true. These aren't like array bounds checks,
+> where missing one case can trash memory. Nothing particularly
+> bad happens, and the predicate will likely get checked soon -- as
+> soon as you pass the thing as a parameter.
+>
+> 3. The alternative is putting in pragmas Assert. Those are no better;
+> they'll become false sometimes, but eventually (you hope) you'll
+> trip over another Assert. In other words, the predicate feature
+> is useful despite loopholes.
+
+I don't think these things are at all equivalent. I think everyone knows that
+Assert means "check this here". And that they aren't going to provide any sort
+of protection. But when putting predicates on subtypes, I think there is an
+expectation that they work much more like a constraint (that is, they hold so
+long as the object has the subtype). Subtypes *do* provide that sort of
+protection in Ada (modulo validity and erroneousness), and it is unfortunate to
+lose that property.
+
+That was *surely* my original intent; I wanted these to be checked in the same
+places as constraints, to be optimizable the same as constraints, and so on.
+It's the fact that this hasn't worked out that makes me so uncomfortable.
+
+As such, I think referencing anything but the current instance and true
+constants (and pure functions) in a predicate is dubious. Especially because
+doing so invalidates optimizations (in general, you have to keep rechecking a
+predicate even if you've already proved it true).
+
+> 4. Make that three points.
+
+Or 5. :-)
+
+> 5. Constraints have a giant loophole, too: uninitialized variables.
+> Note that even discriminants can contain uninitialized junk.
+
+Only in erroneous programs. All bets are off really does mean that.
+
+I'm not very interested in programs that are using pragma Suppress, or use
+broken address clauses, or whatever. There isn't much that can be done to help
+those. But I surely worry about programmers who wear their seatbelts (constraint
+checking, predicate checking, etc.) all the time -- I don't want them getting
+bogus results. Especially as those are likely to turn into support calls...
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Tuesday, October 12, 2010 10:01 PM
+
+> In Valencia, one concern was that if you say "X.Comp := ...;", then
+> the predicate of X is not checked. The predicate of Comp is, but not
+> the object as a whole.
+>
+> One way to address this would be to say it *is* checked, if the
+> left-hand side of an assignment is a selected or indexed component.
+> Also if an actual for an [in]out param is such a component.
+>
+> There would still be loopholes, but plugging this obvious one might
+> make some people (including me, I admit!) happier.
+>
+> I'm not sure it's a good idea, but it's far better than the
+> baby/bathwater ideas of Valencia (which of course ALSO imply that no
+> predicate can be checked on "X.Comp := ...;", because there can be
+> none!).
+
+I'm pretty sure it is not a good idea, at least from an implementation
+perspective.
+
+The issue here is that this would be the first check in Ada that would occur
+*after* assignment. That would force the compiler to generate/keep a lot of
+information that it currently does not. That happens because the compiler cannot
+in general evaluate an Ada "Name" twice (I'm referring to the syntactic entity
+"Name" here).
+
+To give a concrete example of what I mean:
+
+Consider the following call:
+
+ P (F1(1).Arr(F2).Int);
+
+where P is procedure P (O : in out Integer);
+ F1 is function F1 (O : Integer) return Rec1;
+ F2 is function F2 return Integer;
+ Arr_Type is type Arr_Type (1..10) of Rec2;
+ Arr is a component of the type of Rec1, of Arr_Type;
+ Int is an Integer component of the type of Rec2;
+ And both Rec1 and Rec2 are subtypes that have a predicate.
+
+Currently, the only check done after the call is the back assignment check,
+which is done before assigning the component. In order to do that back
+assignment, the address of the object passed to the parameter has to be saved
+somewhere during the call. That's important as the body of P might change the
+result of F1 or F2, and we have to assign back into the same object that was
+passed as a parameter. (Note that the same effect can occur if F1 and F2 are
+replaced by global variables.)
+
+Now, to do predicate checks here, we would also have to save the addresses of
+the prefixes F1(1) and F1(1).Arr(F2) before the call for use afterward. This is
+necessary for the same reason: F1 and F2 might be different after the call. This
+is definitely a new mechanism; I'm pretty sure that Janus/Ada doesn't have any
+way to evaluate part of a Name. (I've had to do it for dereferences, and the
+solution was to chop off the .all part of the Name and then evaluate normally.
+But that requires generating the rest of the name with new code; that's not
+tough for .all alone, but gets to be a major mess if the rest is
+".Arr(F2).Int".)
+
+[I believe that invariants escape this problem by only checking at the package
+interface, so only the passed object need be checked, not some prefix.]
+
+A similar problem arises to evaluate assignments:
+
+ F1(1).Arr(F2).Int := 10;
+
+would require saving the addresses of the prefixes F1(1) and F1(1).Arr(F2) when
+the LHS is evaluated so that predicate checks can be done after the assignment
+is finished.
+
+This is clearly going to take significant implementation work, especially as the
+overhead is occurring in a common place such that a lot of optimization effort
+would be justified. (I know we have very complex predicates which we use to
+determine when we can dispense with the saving of the address of the object
+passed as an "in out" parameter; similar efforts would be needed here.)
+
+This isn't a show-stopper, but it promises to make predicates substantially more
+expensive to implement than the current proposals.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Wednesday, October 13, 2010 2:05 AM
+
+> Only in erroneous programs. All bets are off really does mean that.
+
+Uninitialized variables do not make a program erroneous!
+
+****************************************************************
+
+From: Robert Dewar
+Date: Wednesday, October 13, 2010 2:20 AM
+
+They do result in invalid values, which are of course exactly analogous to
+values that do not meet their predicates. But this failure of a value to meet
+its constraints does NOT of itself make a program erroneous.
+
+The statements about variables not meeting their predicates should be analogous
+to the statements in the invalid values section. Basically an invalid value may
+not meet its predicate, so what?
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, October 13, 2010 7:53 AM
+
+> I'm pretty sure it is not a good idea, at least from an implementation
+> perspective.
+
+What if we allowed, instead of required, implementations to check predicates at
+certain additional places?
+
+I can certainly imagine super-checking modes that check more than is required --
+whether or not permission for such modes is given by the RM.
+
+> Consider the following call:
+>
+> P (F1(1).Arr(F2).Int);
+
+This example is illegal -- function results (and their
+subcomponents) are constant. But I understand what you're saying -- you would
+need to save array indices, or addresses of array components.
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, October 13, 2010 9:24 AM
+
+> I personally would prefer to ban access to globals as well.
+
+I agree that might be a useful direction to go in, but only if we have globals
+annotations. Without globals annotations, the only way to forbid accessing
+globals is to forbid calls to user-defined functions, and that's way too
+restrictive.
+
+> If there was a rule that would in fact be implementable and ensured
+> the "predicates are always true", I'd be strongly in favor of it.
+
+I don't believe you. Surely you have some other criteria for such a rule than
+just "implementable"!
+
+> But part of the problem is most of what you say you want to do is
+> *exactly* what I don't think you ought to be doing (more below).
+
+Ah, the punitive school of language design. ;-)
+
+What about my example of records with mostly-constant components?
+Why "ought" I avoid asserting properties involving such?
+
+> I don't agree in the sense that I don't think it is very valuable to
+> treat chapter 13 as some sort of second-class citizen.
+
+But you HAVE to. And you DO, below, where you say "I'm not very interested in
+programs that are using pragma Suppress, ...". If you want to design a language
+feature that has some useful property, you MUST allow that property to be
+violated by chap-13-ish features.
+
+>... And I suspect that if you
+> asked 6 Ada lawyers what features were included in this all-bets are
+>off category, you'd get 9 answers.
+
+Well, I think I know what I mean by "chap-13-ish". Do I need to spell it out?
+
+> > 1. I can think of a few cases where using global vars in predicates
+> > is reasonable.
+>
+> Please give one or more examples.
+
+I have a bunch of items. Each item has a current state, which is an enum. For
+each state, there is a collection of items in that state. Certain state
+transitions are valid. When one item is processed (changes state), other
+dependent items get moved to different states. There are algorithms like "while
+there are items in state X, process one of them". I wish to assert that the
+enum matches which collection the item is in (and it's not in two or zero
+collections).
+
+Every state transition is done by passing an item to a procedure, so don't worry
+that somebody might poke the enum out of the blue, or call "Set_To_Empty" on the
+collection (either of which would invalidate the predicate). No language rule
+ensures this -- it's just my design, and there's a comment saying so.
+
+I probably don't give write access to that enum to clients.
+
+This is a real example (simplified) that I've written more than once.
+I used pragmas Assert in each procedure to ensure my predicate, and help
+document it. A Predicate saying "this is true every time you pass an item to
+one of the state-changing ops" is clearly superior to Asserts, even in the
+presence of loopholes.
+
+>...Subtypes *do* provide that
+> sort of protection in Ada (modulo validity and erroneousness), and it
+>is unfortunate to lose that property.
+
+In other words, subtypes do NOT provide that protection! I'll let you get away
+with "modulo erroneousness" if you're talking about chap-13-ish features. But
+uninit vars are not a chap-13-ish feature. I use them all over the place
+(taking care not to look at them until initialized).
+
+Uninit vars are a huge loophole in the "constraints always true" property, so I
+reject the argument that predicates should have no (non-chap-13) loopholes "just
+like constraints".
+
+> That was *surely* my original intent; I wanted these to be checked in
+> the same places as constraints, to be optimizable the same as
+> constraints, and so on. It's the fact that this hasn't worked out that
+> makes me so uncomfortable.
+
+I agree with the discomfort. In a from-scratch language design, I'd address it.
+But Ada just doesn't have the necessary mechanisms to address it, short of
+onerous restrictions.
+
+> > 5. Constraints have a giant loophole, too: uninitialized variables.
+> > Note that even discriminants can contain uninitialized junk.
+>
+> Only in erroneous programs. All bets are off really does mean that.
+
+Robert corrected your misuse of "erroneous" here, so I'll assume you mean "Only
+in wrong programs". The same is true of predicates with loopholes -- no matter
+what the loopholes are, if you use them to do wrong things, then your program is
+wrong.
+
+> I'm not very interested in programs that are using pragma Suppress, or
+> use broken address clauses, or whatever. There isn't much that can be
+> done to help those.
+
+So you agree with me about chap-13-ish features.
+
+>... But I surely worry about programmers who wear their seatbelts
+>(constraint checking, predicate checking, etc.) all the time -- I don't
+>want them getting bogus results. Especially as those are likely to
+>turn into support calls...
+
+Well, yeah. We get a lot of support calls about uninit vars.
+Too bad there's no language feature to prevent those bugs.
+I fixed an uninit var in my own code about a month ago -- the bug had existed
+for a year, and showed up only on a certain operating system -- on most systems,
+it just happened to have a value that obeyed its constraint. I felt kind of
+stupid. :-(
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 1:37 PM
+
+> > I'm pretty sure it is not a good idea, at least from an implementation
+> > perspective.
+>
+> What if we allowed, instead of required, implementations to check
+> predicates at certain additional places?
+>
+> I can certainly imagine super-checking modes that check more than is
+> required -- whether or not permission for such modes is given by the
+> RM.
+
+Possible, I suppose, but I thought we had discussed that during one of the
+meetings and rejected it. (But I may be misremembering.)
+
+> > Consider the following call:
+> >
+> > P (F1(1).Arr(F2).Int);
+>
+> This example is illegal -- function results (and their
+> subcomponents) are constant. But I understand what you're saying --
+> you would need to save array indices, or addresses of array
+> components.
+
+Not necessarily: dereferences are implicit in Ada. (But I forgot to include it
+in my description, so of course you are right.)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 1:34 PM
+
+> > Only in erroneous programs. All bets are off really does mean that.
+>
+> Uninitialized variables do not make a program erroneous!
+
+I was talking about "discriminants containing garbage". That can't happen unless
+the program is erroneous (discriminants are always initialized) - possibly from
+reading an abnormal value. "Invalid" representations are a different issue, but
+the language rules prevent problems with them.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 2:04 PM
+
+...
+> > > 5. Constraints have a giant loophole, too: uninitialized variables.
+> > > Note that even discriminants can contain uninitialized junk.
+> >
+> > Only in erroneous programs. All bets are off really does mean that.
+>
+> Robert corrected your misuse of "erroneous" here, so I'll assume you
+> mean "Only in wrong programs". The same is true of predicates with
+> loopholes -- no matter what the loopholes are, if you use them to do
+> wrong things, then your program is wrong.
+
+I stand by my original statement, but I should have elaborated on it. First, I
+was responding to the "discriminants can contain uninitialized junk" statement,
+not the part about uninitialized variables in general. Although I could have
+covered the "abnormal" object case as well. (And no, I don't care *why* the
+program is erroneous; I absolutely would not limit it to chapter 13 features
+unless you take a very expansive view of what those are. Perhaps you are doing
+that, I don't know because the concept is not at all well-defined.)
+
+But invalid values (which have to be scalar) are a different kettle of fish, and
+I really don't agree with your assertion. While it is obvious that they can be
+out of range at a particular point in the program, the language rules ensure
+that they will be checked before they can do any harm. So the only effect of
+allowing invalid values in an Ada program is to move a check from one point to
+another.
+
+While I agree this is a loophole, calling it "giant" seems wrong to me. Ada
+usually does operations on the base types, so you have to be prepared for this
+behavior in any case (with intermediate rules, for one example). And this
+"loophole" is far less troublesome than the "predicate changing values" problem,
+because the check (whenever it is made) is always going to return the same
+result. Thus the effect is going to be moving a check later in the program,
+rather than failing to detect a problem at all.
+
+As I've said, I want to be able to use the same mechanisms for predicates as for
+constraints. That clearly includes the entire invalid value machinery, so
+anything having to do with that alone is clearly OK. But assigning a component
+that changes the predicate is a very different problem from invalid values (a
+known valid value cannot become invalid short of erroneous execution).
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, October 13, 2010 4:36 PM
+
+> I stand by my original statement, but I should have elaborated on it.
+> First, I was responding to the "discriminants can contain uninitialized junk"
+> statement, not the part about uninitialized variables in general.
+
+Oh. Sorry. Here's what I mean:
+
+ type Color is (Red, ...);
+
+ type T(Discrim: Color) is ...;
+
+ X : Color; -- uninitialized
+
+ Y : T(Discrim => X);
+
+This gives a possibly-invalid value to Discrim.
+I don't THINK that's erroneous. And I don't think it requires a run-time check,
+since the subtype of Discrim is the same as that of X.
+
+Am I wrong?
+
+>...Although I
+> could have covered the "abnormal" object case as well. (And no, I don't care
+> *why* the program is erroneous; I absolutely would not limit it to chapter
+> 13 features unless you take a very expansive view of what those are.
+> Perhaps you are doing that, I don't know because the concept is not at
+> all well-defined.)
+
+It's pretty well-defined in my brain. ;-) I just haven't explained it in
+detail. Basically, it's the features that interface to stuff outside the
+pristine Ada world (hardware, or other languages). These features are inherently
+dangerous, but you can isolate them in packages.
+
+Uninit vars are not a chap-13-ish feature, because they are not inherently
+dangerous, and you can't isolate them. They are dangerous in Ada, but not
+inherently so. (Java has a pretty-good story for uninit vars, at least in the
+local case -- and the bug I mentioned that I caused a year ago and fixed a month
+ago was a local uninit var, which would have been caught at compile time in
+Java.)
+
+I also include pragma Suppress (or equivalent switches) in "chap-13-ish".
+It can't be isolated in the same way, but it can be controlled easily (turn the
+checks back on!).
+
+You're not alone in thinking my idea (that chap-13-ish features are "special")
+is bogus. I think Robert disagrees with me -- he says things like "address
+clauses are a perfectly good feature of Ada, nothing special about them".
+
+> But invalid values (which have to be scalar) are a different kettle of
+> fish, and I really don't agree with your assertion. While it is
+> obvious that they can be out of range at a particular point in the
+> program, the language rules ensure that they will be checked before
+> they can do any harm. So the only effect of allowing invalid values in
+> an Ada program is to move a check from one point to another.
+
+That's often the case, but the check might be moved to "never"
+in some cases.
+
+ X: Integer range 1..10;
+
+ if ... then
+ X := Func(...);
+ end if;
+ ...
+ if ... then -- programmer hopes this condition is implied by earlier one
+ if X >= 1 then
+ Print(X);
+ end if;
+ end if;
+
+might print -999.
+
+>... (a known valid value cannot become invalid short of erroneous
+>execution).
+
+That could be true or false, depending on what you mean.
+
+ Foo: Color; -- could be invalid;
+ Bar: Color := Red; -- Bar is valid
+ Bar := Foo; -- Bar becomes invalid (maybe)
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, October 13, 2010 4:44 PM
+
+> > I can certainly imagine super-checking modes that check more than is
+> > required -- whether or not permission for such modes is given by the
+> > RM.
+>
+> Possible, I suppose, but I thought we had discussed that during one of
+> the meetings and rejected it. (But I may be misremembering.)
+
+I had trouble with doing the wording, so I rejected the idea.
+Not sure if we discussed that in a meeting -- maybe one of the sub-ARG phone
+meetings. But maybe I should try harder.
+
+The problem is: you can't just allow the implementation to check predicates any
+time they like. But maybe "any time a component is modified or any time a value
+is read", or something like that, might work.
+
+> > > Consider the following call:
+> > >
+> > > P (F1(1).Arr(F2).Int);
+> >
+> > This example is illegal -- function results (and their
+> > subcomponents) are constant. But I understand what you're saying --
+> > you would need to save array indices, or addresses of array
+> > components.
+>
+> Not necessarily: dereferences are implicit in Ada. (But I forgot to
+> include it in my description, so of course you are right.)
+
+That was my first reaction -- you're missing a ".all" somewhere.
+But as soon as you do ".all", you're not talking about a component of the outer
+object anymore.
+
+Which reminds me of another case (I've mentioned before) where I want predicates
+to refer to globals. In GNAT, a Node_Id is an index into some table, and I want
+to say:
+
+ subtype Expression_Node_Id is Node with
+ Predicate => Node_Kind(Expression_Node_Id) in Expression_Node_Kind;
+
+Node_Kind is a function (so I want calls!), and the table is global (so I want
+globals!), but it's not evil, because the node kind rarely changes.
+
+****************************************************************
+
+From: Tucker Taft
+Date: Wednesday, October 13, 2010 5:50 PM
+
+>> I stand by my original statement, but I should have elaborated on it.
+>> First, I was responding to the "discriminants can contain uninitialized junk"
+>> statement, not the part about uninitialized variables in general.
+>
+> Oh. Sorry. Here's what I mean:
+>
+> type Color is (Red, ...);
+>
+> type T(Discrim: Color) is ...;
+>
+> X : Color; -- uninitialized
+>
+> Y : T(Discrim => X);
+>
+> This gives a possibly-invalid value to Discrim.
+> I don't THINK that's erroneous. And I don't think it requires a
+> run-time check, since the subtype of Discrim is the same as that of X.
+>
+> Am I wrong?
+
+It depends. If a compiler doesn't do the constraint check on setting the
+discriminant, then it has to worry about this case everywhere, since
+uninitialized variables are not allowed to lead to erroneous execution (they are
+"bounded" errors, according to the RM). Compilers differ in how they "bound"
+the effects of uninitialized variables. AdaMagic makes the distinction between
+objects whose declared subtype is "trusted" and those for which it isn't. We
+don't allow you to assign the value of an "untrusted" object into a "trusted"
+one without a constraint check.
+
+I think pretty much all compilers have to have these two categories, but how
+they define the two categories may vary.
+
+In our compiler, all object that are initialized at their declaration point, all
+discriminants, all IN and IN-out parameters, and all record components with a
+default expression, are considered trusted. I don't know what is the rule for
+other compilers. I believe Rational at one point trusted everything, by
+automatically default-initializing scalars to some in-range value. I think that
+can hide bugs. An alternative approach is to assign an out-of-range default
+value to all untrusted objects, and then you are likely to catch most
+inappropriate use. AdaMagic takes the approach of letting any old stack "junk"
+be the default initial value for an untrusted object, and rely on normal
+constraint checks to find most cases of uninitialized variables.
+
+In any case, I would be surprised if a compiler put discriminants in the
+"untrusted" category, unless it put *everything* in the untrusted category.
+Perhaps that is what GNAT does, by doing checks on every use of a scalar that
+could lead to something erroneous, like a wild jump or a wild store, unless
+there is "local" knowledge about the value being in range.
+
+But if the compiler has at least some scalar objects in the trusted category,
+then I would predict that discriminants are "trusted" and would require a check
+on initialization from an untrusted scalar object, even if it is of the same
+subtype.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 6:14 PM
+
+Thanks for the detailed reply. I was just writing a less-detailed one, which
+I've round-filed.
+
+Janus/Ada has a similar concept (called "known to be valid"), and discriminants
+are always in that category. A discriminant constraint like the one in Bob's
+example would always be checked (subtype information is ignored in this case, as
+the source is not "known to be valid").
+
+I'm sure it is technically true that discriminants could be allowed to be
+invalid, but I'm dubious that it is practical to prevent erroneous execution if
+they are. Declaration and use of discriminant-dependent components would be,
+umm, interesting to implement without the certainty that the discriminants are
+valid for all objects that aren't abnormal. That's especially true for a
+compiler that uses a max-size implementation strategy (how would the compiler
+prevent access to non-existent memory if the bounds of the component allow it?
+Multiple checks? Yuk.)
+
+****************************************************************
+
+From: Bob Duff
+Date: Wednesday, October 13, 2010 7:02 PM
+
+> Thanks for the detailed reply. I was just writing a less-detailed one,
+> which I've round-filed.
+
+OK, Tucker and Randy have replied. So the conclusion is: I'm (technically)
+right that discrims can be invalid according to the RM, but it's really not a
+problem in practice, and all compilers actually check that discrims are in
+range.
+
+Right?
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 8:35 PM
+
+Right. (At least all Ada 95 and later compilers. Ada 83 didn't have any of the
+validity stuff, and allowed uninitialized variables to cause erroneousness. I
+think.)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 9:05 PM
+
+...
+> >... (a known valid value cannot become invalid short of erroneous
+> >execution).
+>
+> That could be true or false, depending on what you mean.
+>
+> Foo: Color; -- could be invalid;
+> Bar: Color := Red; -- Bar is valid
+> Bar := Foo; -- Bar becomes invalid (maybe)
+
+I meant in the sense of what Tucker called "trusted" and Janus/Ada calls
+internally "known to be valid". There's a compiler bug if non-erroneous
+execution causes such a value to become invalid. It's implementation-defined
+what values (if any) have that property. A compiler (absent other local
+information) can only remove subtype range checks if the source is known to be
+valid or the target is NOT known to be valid, and the subtypes are the same or
+the target has a static subtype and the source has a smaller maximum range.
+(Array indexing is required by the language to be treated as a target that is
+known to be valid: that is, execution cannot be erroneous if an invalid value is
+used, and that can only be guaranteed by making the check or having a known to
+be valid source).
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Wednesday, October 13, 2010 9:13 PM
+
+> > Not necessarily: dereferences are implicit in Ada. (But I forgot to
+> > include it in my description, so of course you are right.)
+>
+> That was my first reaction -- you're missing a ".all" somewhere.
+> But as soon as you do ".all", you're not talking about a component of
+> the outer object anymore.
+
+True, but the designated type of the access type could have a predicate. One
+would hope that got checked the same way!
+
+That is, change my original explanation of F1 to:
+
+ F1 is function F1 (O : Integer) return access Rec1;
+
+If Rec1 has a predicate, we have the same issue. (And you'd have to save the
+returned access value somewhere.)
+
+> Which reminds me of another case (I've mentioned before) where I want
+> predicates to refer to globals. In GNAT, a Node_Id is an index into
+> some table, and I want to say:
+>
+> subtype Expression_Node_Id is Node with
+> Predicate => Node_Kind(Expression_Node_Id) in
+> Expression_Node_Kind;
+>
+> Node_Kind is a function (so I want calls!), and the table is global
+> (so I want globals!), but it's not evil, because the node kind rarely
+> changes.
+
+This example seems a bit dubious, since the point of having static predicates is
+to completely replace a function like Node_Kind with a subtype like
+Expression_Node_Id. Not that you could completely replace the function calls in
+existing code, but surely reduce the use.
+
+****************************************************************
+
+From: Bob Duff
+Date: Thursday, October 14, 2010 7:35 AM
+
+> Right. (At least all Ada 95 and later compilers. Ada 83 didn't have
+> any of the validity stuff, and allowed uninitialized variables to
+> cause erroneousness. I think.)
+
+Actually, it's not right. The following program prints "zero", and I don't
+think that's a GNAT bug.
+
+gnatmake -g -gnata -gnatwa -gnato -f uninit.adb
+
+uninit.adb:12:07: warning: variable "X" is read but never assigned
+uninit.adb:15:20: warning: condition can only be True if invalid values present
+
+So my claim is not just theoretical -- discriminants can be invalid in practice.
+(I must admit, it took quite a bit of playing around to trick the compiler!)
+
+with Text_IO; use Text_IO;
+
+procedure Uninit is
+
+ procedure Q is
+ type Int is range 1..10;
+ type T(Discrim: Int) is
+ record
+ null;
+ end record;
+ X : Int;
+ Y : T(Discrim => X);
+ begin
+ if Y.Discrim = 0 then
+ Put_Line("zero");
+ else
+ Put_Line("nonzero");
+ end if;
+ end Q;
+
+begin
+ Q;
+end Uninit;
+
+****************************************************************
+
+From: Tucker Taft
+Date: Thursday, October 14, 2010 9:46 AM
+
+> So my claim is not just theoretical -- discriminants can be invalid in
+> practice. (I must admit, it took quite a bit of playing around to
+> trick the compiler!)
+
+That confirms my guess that *everything* is untrusted in GNAT. So it would be
+interesting to use Y.Discrim as an index into an array indexed by "Int", and see
+whether it detects the problem then. If it doesn't, then I believe there *is* a
+GNAT bug. It needs to do the constraint check *somewhere* before the invalid
+value gets used as an array index.
+
+****************************************************************
+
+From: Bob Duff
+Date: Thursday, October 14, 2010 10:01 AM
+
+Right, and it does. I just tried it, and it gets Constraint_Error when using
+that discrim as an array index. For both reading and modifying the array
+element.
+
+I think GNAT may have been too lax years ago, but those bugs have been fixed.
+
+****************************************************************
+
+From: Edmond Schonberg
+Date: Thursday, October 14, 2010 10:15 AM
+
+> That confirms my guess that *everything* is untrusted in GNAT. So it
+> would be interesting to use Y.Discrim as an index into an array
+> indexed by "Int", and see whether it detects the problem then. If it
+> doesn't, then I believe there *is* a GNAT bug. It needs to do the
+> constraint check *somewhere* before the invalid value gets used as an
+> array index.
+
+GNAT always does a constraint check on an indexed assignment, so there is
+fortunately no bug there. It doesn't check on an indexed retrieval.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 5:38 PM
+
+> That confirms my guess that *everything* is untrusted in GNAT. So it
+> would be interesting to use Y.Discrim as an index into an array
+> indexed by "Int", and see whether it detects the problem then. If it
+> doesn't, then I believe there *is* a GNAT bug. It needs to do the
+> constraint check *somewhere* before the invalid value gets used as an
+> array index.
+
+Why? I thought the only restriction was that you can't have it causing
+erroneousness (whatever that exactly means). What GNAT does in a case like this
+is check it if it is on the left side (a store), but not check it on a load.
+That seems OK to me. On a load, you just propagate some possibly invalid value.
+On a store you could do an erroneous store and you can't allow that.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 5:38 PM
+
+> Right, and it does. I just tried it, and it gets Constraint_Error
+> when using that discrim as an array index. For both reading and
+> modifying the array element.
+
+I am surprised you get a CE for the read ...
+interesting ...
+
+****************************************************************
+
+From: Bob Duff
+Date: Thursday, October 14, 2010 5:53 PM
+
+I'm not surprised. I think we need to do that, because otherwise a wild memory
+reference (even a read) can cause a segfault. (We could try to turn that
+segfault into a Constraint_Error, but it would be hard, and we don't -- I think
+we turn segfaults into Storage_Error always.)
+
+On an embedded machine without memory mapping hardware, reading from a
+nonexistent address doesn't fault, but on some hardware it hangs. So we need
+the check on those machines, too.
+
+I think GNAT is RM-conformant in this area, after much discussion of such issues
+in years past! The RM rules are not crystal clear, unfortunately.
+
+I hate bounded errors. "Erroneous" is a menace, but at least it's clear that it
+means "don't do that". A bounded error requires a full page of RM verbiage to
+explain what the bounds are, and nobody understands it.
+
+****************************************************************
+
+From: Bob Duff
+Date: Thursday, October 14, 2010 5:27 PM
+
+> > Node_Kind is a function (so I want calls!), and the table is global
+> > (so I want globals!), but it's not evil, because the node kind
+> > rarely changes.
+>
+> This example seems a bit dubious, since the point of having static
+> predicates is to completely replace a function like Node_Kind with a
+> subtype like Expression_Node_Id.
+
+Heh? You still want to query Node_Kind when you want to know what sort of
+expression it is. I guess I miss your point -- this example doesn't seem at all
+dubious to me. I can't imagine how one would express the required property of
+Expression_Node_Id without calling something like Node_Kind.
+
+>...Not that you could completely replace the function calls in
+>existing code, but surely reduce the use.
+
+I think it's fair to talk about new code.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 6:15 PM
+
+> Heh? You still want to query Node_Kind when you want to know what
+> sort of expression it is. I guess I miss your point -- this example
+> doesn't seem at all dubious to me. I can't imagine how one would
+> express the required property of Expression_Node_Id without calling
+> something like Node_Kind.
+>
+>> ...Not that you could completely replace the function calls in
+>> existing code, but surely reduce the use.
+>
+> I think it's fair to talk about new code.
+
+I agree with BOb on this, seems a perfectly reasonable use (in fact it is the
+usage example that persuaded me that dynamic predicates have some value :-))
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 6:22 PM
+
+>> I am surprised you get a CE for the read ...
+>> interesting ...
+>
+> I'm not surprised. I think we need to do that, because otherwise a
+> wild memory reference (even a read) can cause a segfault. (We could
+> try to turn that segfault into a Constraint_Error, but it would be
+> hard, and we don't -- I think we turn segfaults into Storage_Error
+> always.)
+
+For me, it is perfectly fine for the use of an invalid value to cause a
+segfault. Yes, language lawyers might mumble, but really I don't care much. All
+that you want is an exception, or program termination with an error, or
+something else reasonable.
+
+In fact why should language lawyers mumble:
+
+> 11 If the representation of the object does not represent a value of the
+> object's type, the semantics of operations on such representations is
+> implementation-defined, but does not by itself lead to erroneous or
+> unpredictable execution, or to other objects becoming abnormal.
+
+Seems to me that causing a segfault if the invalid value results in an out of
+range address is quite within the realm ofr implementation defined stuff that is
+not erroneous or unpredictable (obviously you can't exactly predict behavior for
+uninitialized values :-))
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 6:25 PM
+
+> On an embedded machine without memory mapping hardware, reading from a
+> nonexistent address doesn't fault, but on some hardware it hangs. So
+> we need the check on those machines, too.
+
+I don't know what GNAT targets you are talking about here, we get faults on all
+machines (that's how we do stack checking after all!) All machines we run on
+have memory mapping hardware!
+
+> I hate bounded errors. "Erroneous" is a menace, but at least it's
+> clear that it means "don't do that". A bounded error requires a full
+> page of RM verbiage to explain what the bounds are, and nobody
+> understands it.
+
+I think I understand it just fine, and I like the idea! Erroneousness is much
+too course!
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 14, 2010 8:28 PM
+
+> Heh? You still want to query Node_Kind when you want to know what
+> sort of expression it is. I guess I miss your point -- this example
+> doesn't seem at all dubious to me. I can't imagine how one would
+> express the required property of Expression_Node_Id without calling
+> something like Node_Kind.
+
+I must have misunderstood your example. What kind of thing is Node? What does
+Node_Kind do? I had presumed that Node was some sort of enumeration, but looking
+at this again, you may have meant something else. From the looks of it, it seems
+like Node_Kind is a really strange way to extract the discriminant value from a
+some sort of Node record type. I wouldn't do things that way (I leave the
+discriminant(s) visible), but I suppose it is reasonable to wrap discriminants
+in a function call. OTOH, if the function is referencing non-discriminants, then
+they can be changed at will, and the entire thing is iffy (especially as the
+only good reason for using non-discriminants is so that they can be changed
+easily -- we do that in some cases in our compiler and I surely would not want
+to have any predicates depending on that).
+
+You also said something about a table: I can't begin to imagine what the purpose
+of that is, so I can't make a judgement on how reasonable it is.
+
+> >...Not that you could completely replace the function calls in
+> >existing code, but surely reduce the use.
+>
+> I think it's fair to talk about new code.
+
+In new code, don't hide discriminants. :-) Then you don't need any functions (at
+least not for what this purpose seems to be).
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 14, 2010 8:44 PM
+
+> In fact why should language lawyers mumble:
+>
+> > 11 If the representation of the object does not represent a value of the
+> > object's type, the semantics of operations on such representations is
+> > implementation-defined, but does not by itself lead to erroneous or
+> > unpredictable execution, or to other objects becoming abnormal.
+>
+> Seems to me that causing a segfault if the invalid value results in an
+> out of range address is quite within the realm ofr implementation
+> defined stuff that is not erroneous or unpredictable (obviously you
+> can't exactly predict behavior for uninitialized values :-))
+
+Gosh. I would have said that a segfault is *exactly* the definition of erroneous
+behavior, as it is not something that could be described by the normally defined
+semantics of an Ada program. (It would be OK if it is turned into an exception,
+through, as that is normally defined semantics. In particular, turning it into
+Storage_Error would seem to be OK, since that can be raised for any reason
+anywhere.)
+
+But I'd also worry about invalid reads that don't segfault. I would be
+especially concerned if such an invalid read happened to touch a memory-mapped
+device. I recall that there used to be devices that only allowed values to be
+read once (our CP/M disk controller was like that - yes I know that was circa
+1979). Touching such a device because of a wayward read would cause data loss
+and who knows what else. And I can't think of any practical way that the
+programmer of such a device could protect themselves if any array read could
+cause trouble.
+
+Bob also mentioned hardware that hung on accesses to non-existent memory. I've
+also programmed that sort of system (but yes, a long time ago).
+
+Even if the letter of the language allows invalid reads, it seems that you would
+be hoping that no customer ever had an unusual system where an extra read would
+do damage. That's not a bet I'd want to make.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 8:46 PM
+
+> Especially as the only good reason for using non-discriminants is so
+> that they can be changed easily -- we do that in some cases in our
+> compiler and I surely would not want to have any predicates depending
+> on that.
+
+Nope, the decision in the GNAT sources is NOT to use discriminants because it
+makes it too difficult to do untyped traversals of the tree.
+
+> In new code, don't hide discriminants. :-) Then you don't need any
+> functions (at least not for what this purpose seems to be).
+
+I don't think we would change the decision in GNAT if we were starting from
+scratch, the compiler is full of untyped traversals of the tree.
+
+Never assume that the particular style you choose for writing code is the only
+one that has to be catered to!
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 8:52 PM
+
+> Gosh. I would have said that a segfault is *exactly* the definition of
+> erroneous behavior, as it is not something that could be described by
+> the normally defined semantics of an Ada program. (It would be OK if
+> it is turned into an exception, through, as that is normally defined
+> semantics. In particular, turning it into Storage_Error would seem to
+> be OK, since that can be raised for any reason anywhere.)
+
+Well we significantly disagree, and since you can't find the word segfault in
+the RM, you are going to have a hard time proving your point. For me erroneous
+means ANYTHING can happen, but if you say that your impl-defined behavior for
+some bounded error is that any of the following can occur, and include segfault,
+that seems reasonable, and is definitely NOT unbounded behavior.
+
+> But I'd also worry about invalid reads that don't segfault. I would be
+> especially concerned if such an invalid read happened to touch a
+> memory-mapped device. I recall that there used to be devices that only
+> allowed values to be read once (our CP/M disk controller was like that
+> - yes I know that was circa 1979). Touching such a device because of a
+> wayward read would cause data loss and who knows what else. And I
+> can't think of any practical way that the programmer of such a device
+> could protect themselves if any array read could cause trouble.
+
+Well again, this is not unbounded erroneousness, and would have to be
+documented, but most likely would not be a good idea to allow.
+
+> Bob also mentioned hardware that hung on accesses to non-existent memory.
+> I've also programmed that sort of system (but yes, a long time ago).
+
+I know of no such hardware, certainly not true of any of the GNAT Pro targets.
+
+> Even if the letter of the language allows invalid reads, it seems that
+> you would be hoping that no customer ever had an unusual system where
+> an extra read would do damage. That's not a bet I'd want to make.
+
+We don't bet, we know the hardware we run on!
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 14, 2010 9:19 PM
+
+> We don't bet, we know the hardware we run on!
+
+I know this sort of thing happened with our compiler back in the dark ages. (Bob
+seems to have such a memory as well, judging from his messages.) But I can
+believe that you aren't encountering such hardware anymore, so maybe it's just a
+case of continuing to worry about issues that are OBE these days.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 9:03 PM
+
+Actually I will say that I thought the intent of talking about non-erroneous
+behavior was precisely to capture the fact that a wild store is unacceptable,
+but a wild load may be acceptable. So Randy's viewpoint is a complete surprise
+to me.
+
+Similar to an IF possibly not thinking a boolean value is true or false, but
+CASE needs to check since a wild jump is unacceptable.
+
+****************************************************************
+
+From: Tucker Taft
+Date: Thursday, October 14, 2010 9:31 PM
+
+A wild load is fine so long as its effect can be "bounded." I agree that a
+segmentation fault is acceptable (or raising Storage_Error I suppose, if that
+was a seg fault turns into).
+
+I don't think doing something that hangs indefinitely or causes some hardware
+device to start misbehaving would be acceptable. I am familiar with hardware
+which (mis)behaved in this way, but as Randy has admitted, this was a long time
+ago. If you are comfortable that for your current targets a wild load has
+bounded ill effects, then it seems like you are fine.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 9:39 PM
+
+Right, I agree with the above
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 9:06 PM
+
+I have the following question about where predicates are set, consider
+
+ subtype A1 is Integer range 1 .. 10;
+
+ subtype A2 is Integer with
+ predicate => A in 1 .. 10;
+
+What are the differences between where the range check is made for A1 and A2.
+
+BTW, I know predicates are not constraints for language lawyers, how about for
+users. I suspect that the reasonable thing is for users to think of predicates
+as being like constraints?
+
+Accordingly, I wonder whether Constraint_Error should be raised instead of
+Assertion_Error when predicates fail.
+
+Basicaly my question is, how important is it to pester the programmer with an
+educational message saying "predicates are NOT constraints!"
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 14, 2010 9:21 PM
+
+> Basicaly my question is, how important is it to pester the programmer
+> with an educational message saying "predicates are NOT constraints!"
+
+That was my point when I was talking to Bob about expectations. I think it would
+be hard to educate people that predicates and constraints are different in
+significant ways, and I'm pretty sure that most users will think of them as the
+same. Thus I worry about cases where they're *not* the same.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 9:36 PM
+
+Sure, that's reasonable, the question is whether the differences end up being in
+the significant or insignificant category. And for sure the fact that
+Assertion_Error instead of CE is raised seems significant (for one thing it
+seems to mean that optimizations applying to CE do not apply here?)
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Thursday, October 14, 2010 9:28 PM
+
+> > Especially as the only good reason for using non-discriminants is so
+> > that they can be changed easily -- we do that in some cases in our
+> > compiler and I surely would not want to have any predicates depending
+> > on that.
+>
+> Nope, the decision in the GNAT sources is NOT to use discriminants
+> because it makes it too difficult to do untyped traversals of the
+> tree.
+
+Not sure at all what this means. Traversals (that is reads) are not likely to be
+a problem no matter how the nodes are implemented. I can imagine having problems
+if you needed to change the kind of a node when it is already linked in a tree,
+but not with traversal.
+
+> > In new code, don't hide discriminants. :-) Then you don't need any
+> > functions (at least not for what this purpose seems to be).
+>
+> I don't think we would change the decision in GNAT if we were starting
+> from scratch, the compiler is full of untyped traversals of the tree.
+>
+> Never assume that the particular style you choose for writing code is
+> the only one that has to be catered to!
+
+For the record, the only reason that we used discriminants in tree nodes was for
+the purposes of storage minimization. Ada doesn't let you use variants unless
+you use discriminants. And there definitely were problems with using
+discriminants rather than some sort of components. (We later found that using
+the variants helped with debugging, as it made referencing unused fields in
+nodes raise Constraint_Error. But that was a lucky side-effect, not something we
+planned for.)
+
+But I still don't think I would have used functions.
+
+Anyway, I agree with you about programming style; that's why I asked Bob for
+these examples in the first place.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Thursday, October 14, 2010 9:39 PM
+
+> Not sure at all what this means. Traversals (that is reads) are not
+> likely to be a problem no matter how the nodes are implemented. I can
+> imagine having problems if you needed to change the kind of a node
+> when it is already linked in a tree, but not with traversal.
+
+In the Alsys compiler a complex discriminated structure was used for the tree,
+covering pages of code (the type definition). Traversing the tree meant a huge
+complex case statement where each kind of node had to be separately traversed.
+We avoid this in GNAT
+
+> For the record, the only reason that we used discriminants in tree
+> nodes was for the purposes of storage minimization. Ada doesn't let
+> you use variants unless you use discriminants. And there definitely
+> were problems with using discriminants rather than some sort of
+> components. (We later found that using the variants helped with
+> debugging, as it made referencing unused fields in nodes raise
+> Constraint_Error. But that was a lucky side-effect, not something we
+> planned for.)
+
+We achieve that debugging effort with assertions.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 10:25 AM
+
+> I must have misunderstood your example. What kind of thing is Node?
+> What does Node_Kind do? I had presumed that Node was some sort of
+> enumeration, but looking at this again, you may have meant something else.
+
+Node_Id is conceptually a pointer to a variant record (or a class-wide type).
+The Kind field is conceptually the discriminant (or tag).
+
+But it's not implemented that way. Deep down, Node_Id is an integer, which is
+an index into a table (some sort of growable array). There's a function to
+fetch the Kind field (which returns an enum).
+
+So my point is, I want to be able to say:
+
+ Current_Expression: Expression_Node_Id;
+
+where we currently must say:
+
+ Current_Expression: Node_Id;
+
+Whether Node_Id is represented as an access type, or as an index into a table.
+
+>... From the looks
+> of it, it seems like Node_Kind is a really strange way to extract the
+>discriminant value from a some sort of Node record type. I wouldn't do
+>things that way (I leave the discriminant(s) visible), but I suppose it
+>is reasonable to wrap discriminants in a function call.
+
+There's no discriminant at the Ada level. We think of Kind as a discriminant of
+a variant record, but in fact it's not a discriminant, and there's no variant
+record. It's all simulated by accessor functions and whatnot.
+
+The actual record contains things like:
+
+ Field1 : Union_Id;
+ Field2 : Union_Id;
+ Field3 : Union_Id;
+ Field4 : Union_Id;
+ Field5 : Union_Id;
+
+but these are all hidden behind accessor functions, such as:
+
+ function Component_List
+ (N : Node_Id) return Node_Id is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Record_Definition
+ or else NT (N).Nkind = N_Variant);
+ return Node1 (N);
+ end Component_List;
+
+where Node1 fetches Field1:
+
+ function Node1 (N : Node_Id) return Node_Id is
+ begin
+ pragma Assert (N <= Nodes.Last);
+ return Node_Id (Nodes.Table (N).Field1);
+ end Node1;
+
+As Robert said, one advantage of this design is that we can write things like
+"Walk_Subnodes_Of_Node" in a few lines of code, whereas the variant record
+design would require a case statement with thousands of lines, and the tagged
+type design would require thousands of lines of overriding "Walk" methods.
+
+Another advantage (over access types pointing to variant records or class-wide
+types) is the ease of making the data structures persistent.
+
+>... OTOH, if the function
+> is referencing non-discriminants, then they can be changed at will, ...
+
+No, that's the point you keep missing. Sure, Ada allows non-discrim components
+to be changed, but the designer of the program can easily hide those components
+so they cannot be changed, or can only be changed in controlled ways.
+
+We could have put those "Field1 : Union_Id;" components in a visible part
+somewhere, and let folks change them willy-nilly. But that would be a poor
+design. The fact that poor designs are possible in Ada is irrelevant. In fact,
+that record type is safely buried in a package body.
+
+>...and the
+> entire thing is iffy (especially as the only good reason for using
+>non-discriminants is so that they can be changed easily -- we do that
+>in some cases in our compiler and I surely would not want to have any
+>predicates depending on that).
+
+There are lots of reasons to use discriminants, and lots of other reasons to
+avoid discriminants. Our language design philosophy ought to be that new
+features are agnostic with respect to such design choices. It's really not our
+job to encourage or discourage the use of discriminants.
+
+And it's REALLY not our job to prevent people from wrapping whatever they like
+in a function, including a pseudo-discriminant accessor!
+
+> You also said something about a table: I can't begin to imagine what
+> the purpose of that is, so I can't make a judgement on how reasonable it is.
+
+Well, I don't really think it's our job to pass judgement; as I said, new Ada
+features should be agnostic, to the extent possible.
+
+Anyway, representing pointers as indices into arrays is entirely appropriate in
+some circumstances. If you're coding in SPARK, you have to do that (if you need
+pointers at all), because SPARK doesn't have "access".
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 10:35 AM
+
+> function Component_List
+> (N : Node_Id) return Node_Id is
+> begin
+> pragma Assert (False
+> or else NT (N).Nkind = N_Record_Definition
+> or else NT (N).Nkind = N_Variant);
+> return Node1 (N);
+> end Component_List;
+
+Note that both occurrences of Node_Id above could be subtypes, with predicates
+indicating what Kind of node is expected and returned. (And then the Assert
+could be removed).
+
+We could do the same with pre/post, but predicates are more convenient (can be
+used also for local variables).
+
+Which reminds me: Why are we all hot and bothered by loopholes in predicates,
+when all the other new assertion facilities (pre, post, invariant) have similar
+loopholes?
+
+You want me to say, "Pre => Kind(N) in (N_Record_Definition | N_Variant)"
+but that's no safer -- no language rule prevents Kind from modifying globals or
+components.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 10:52 AM
+
+> > That was my point when I was talking to Bob about expectations. I
+> > think it would be hard to educate people that predicates and
+> > constraints are different in significant ways, and I'm pretty sure
+> > that most users will think of them as the same. Thus I worry about
+> > cases where they're *not* the same.
+
+The main way predicates differ from constraints is that predicates have bigger
+loopholes (cases where they can be false). But constraints have loopholes, too
+(can be false for uninitialized objects), so I'm not too excited about it. I
+already demonstrated yesterday that a discriminant can be out of bounds, and the
+sky didn't fall.
+
+> Sure, that's reasonable, the question is whether the differences end
+> up being in the significant or insignificant category. And for sure
+> the fact that Assertion_Error instead of CE is raised seems
+> significant
+
+I'm puzzled by this comment. You wouldn't normally handle such exceptions, and
+an unhandled CE is pretty-much the same as an unhanlded AE.
+
+I don't really care if we change AE to CE for predicates, but for consistency,
+we should then make pre/post/invariant use CE.
+
+> (for one thing it seems to mean that optimizations applying to CE do
+> not apply here?)
+
+For sure the rules in that area are different for assertions (pragma Assert,
+pre/post, invariants, predicates) than for things like array-bounds checks. But
+I wouldn't call that "significant" from a programmer's point of view.
+
+The programmer's rule is simple: Make sure assertions are true. And make sure
+array indexing is in bounds. The consequences of violating these rules may
+differ, but that's secondary.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 11:15 AM
+
+> I'm puzzled by this comment. You wouldn't normally handle such
+> exceptions, and an unhandled CE is pretty-much the same as an unhanlded AE.
+
+I thought 11.6 permissions only applied to CE and not AE, if they apply to AE
+that's really interesting, but probably wrong!
+
+> I don't really care if we change AE to CE for predicates, but for
+> consistency, we should then make pre/post/invariant use CE.
+
+Maybe yes for invariant, but I am not sure, invariants are very obviously
+different from constraints to me.
+
+For sure not for pre/post
+
+These are nothing to do with constraints, and furthermore this would be a very
+nasty incompatibility with existing implementations.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 11:23 AM
+
+Also it seems to me that predicates should turn on and off like constraints
+(suppress All_Checks, or -gnatp switch in GNAT) rather than on and off like
+assertions (pragma Assertion_Policy, -gnata switch in GNAT).
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 11:25 AM
+
+Note by the way that in GNAT, using the Check_Policy pragma you can turn
+invariants, predicates, postconditions, preconditions on and off separately.
+Assertions always turns all of these on, which I am not sure is ideal, but is
+needed for conformance.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 11:59 AM
+
+> I thought 11.6 permissions only applied to CE and not AE, if they
+> apply to AE that's really interesting, but probably wrong!
+
+11.6 talks about "checks". It doesn't mention CE explicitly; it applies to PE
+as well, for example.
+
+Assertions (including predicates) are not checks, so 11.6 does not apply to
+them, according to the current proposal.
+
+But so what? 11.6 is language-lawyerly. Regular programmers don't understand
+it, and ignore it. Your query was about the programmer's view -- Are predicates
+and constraints pretty much the same thing? I say, "Yes, they are -- the
+differences are details for language lawyers to worry about."
+
+As a user, I would consider:
+
+ subtype T is Integer range 0..Integer'Last;
+
+and:
+
+ subtype T is Integer with Predicate => T >= 0;
+
+to be interchangeable. Both mean "I believe that property is true, and if I'm
+wrong, stop the program and give me some info to help me debug".
+
+> > I don't really care if we change AE to CE for predicates, but for
+> > consistency, we should then make pre/post/invariant use CE.
+>
+> Maybe yes for invariant, but I am not sure, invariants are very
+> obviously different from constraints to me.
+
+Not to me. Constraints, invariants, predicates, and null exclusions all serve
+the same purpose: asserting properties of things. If you think otherwise, you
+must be wearing your Language Lawyer hat.
+
+> For sure not for pre/post
+>
+> These are nothing to do with constraints, and furthermore this would
+> be a very nasty incompatibility with existing implementations.
+
+That's settles it (the compatibility issue).
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 12:05 PM
+
+> Also it seems to me that predicates should turn on and off like
+> constraints (suppress All_Checks, or -gnatp switch in GNAT) rather
+> than on and off like assertions (pragma Assertion_Policy, -gnata
+> switch in GNAT).
+
+The current proposal is that pragma Suppress does not apply to assertions
+(including predicates).
+
+You can turn off predicates with Assertion_Policy, but it has a different
+effect: Suppressing wrong checks causes erroneous behavior, turning off wrong
+predicates does not.
+
+I'm reasonably happy with this state of affairs, but we can certainly discuss
+alternatives.
+
+Note that assertions (including predicates) can be arbitrarily inefficient,
+whereas constraint checks cannot.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 2:27 PM
+
+> But so what? 11.6 is language-lawyerly. Regular programmers don't
+> understand it, and ignore it. Your query was about the programmer's
+> view -- Are predicates and constraints pretty much the same thing? I
+> say, "Yes, they are -- the differences are details for language
+> lawyers to worry about."
+
+They may ignore it, but the compiler doesn't! The permissions to optimize checks
+are important, and IMO should apply to predicate checs.
+
+> As a user, I would consider:
+>
+> subtype T is Integer range 0..Integer'Last;
+>
+> and:
+>
+> subtype T is Integer with Predicate => T>= 0;
+>
+> to be interchangeable. Both mean "I believe that property is true,
+> and if I'm wrong, stop the program and give me some info to help me
+> debug".
+
+That's why I would expect them to raise the same exception
+
+> Not to me. Constraints, invariants, predicates, and null exclusions
+> all serve the same purpose: asserting properties of things.
+> If you think otherwise, you must be wearing your Language Lawyer hat.
+
+The reason invariants are so different from constraints is the inside/outside
+semantics, so they can be very deliberately "violated" and nothing is wrong.
+Programmers DO need to understand this distinction!
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 2:30 PM
+
+> Note that assertions (including predicates) can be arbitrarily
+> inefficient, whereas constraint checks cannot.
+
+I fundamentally disagree with this cavalier attitude to efficiency in this case.
+I think it important that predicates be as efficient as possible (after all you
+think of using them in the compiler, we can't have things in the compiler that
+are arbitrarily inefficient).
+
+ From a formal language lawyer point of view, anything can be arbitrarily
+ inefficient, the formal description of the language has nothing to say about
+ efficiency. If you want to implement constraint checks by a serial search
+ through a table of out of range values, that's bad idea, but not
+ non-conforming.
+
+ From a pragmatic point of view, everything should be as efficient as possible,
+ and the ability to do things efficiently should inform the language design.
+
+I do not understand the distinction you draw here between constraint checks and
+predicates. Makes no sense to me with or without a language lawyer hat on.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 2:57 PM
+
+> > Note that assertions (including predicates) can be arbitrarily
+> > inefficient, whereas constraint checks cannot.
+>
+> I fundamentally disagree with this cavalier attitude to efficiency in
+> this case.
+
+I don't see any "cavalier attitude". It's simply a fact that predicates can
+be arbitrarily slow, whereas constraints are restricted to simple (and
+therefore efficient) checks.
+
+A fact isn't an "attitude", cavalier or otherwise.
+
+>... I think it important that
+> predicates be as efficient as possible (after all you think of using
+>them in the compiler, we can't have things in the compiler that are
+>arbitrarily inefficient).
+
+We turn off pragmas Assert, and constraint checks, in production builds of the
+compiler.
+
+> From a formal language lawyer point of view, anything can be
+> arbitrarily inefficient, the formal description of the language has
+> nothing to say about efficiency.
+
+Of course you know that I know that! I also know how range checks are typically
+implemented, and it's a couple of instructions. Of course any discussion of
+efficiency is totally unrelated to RM conformance!
+
+>...If
+> you want to implement constraint checks by a serial search through a
+>table of out of range values, that's bad idea, but not non-conforming.
+>
+> From a pragmatic point of view, everything should be as efficient as
+> possible, and the ability to do things efficiently should inform the
+> language design.
+
+I'm pretty sure you don't believe "everything should be as efficient as possible",
+because the most efficient thing would be to avoid Assert and Predicate altogether.
+You must mean something else...
+
+I don't understand what "informing" you're wanting here.
+If we allow arbitrary code in procedures (and we do), then procedures can be
+arbitrarily slow. If we allow arbitrary code in predicates, then those can be
+arbitrarily slow, too.
+
+Of course I agree with the general principle that the language design should allow
+for efficient implementations. But I don't see what you're applying that to, here
+-- it doesn't seem to have much to do with the CE vs. AE question, or the exact
+rules for what Assertion_Policy means, or -gnata vs. -gnatp, or anything else we've
+been discussing lately.
+
+> I do not understand the distinction you draw here between constraint
+> checks and predicates. Makes no sense to me with or without a language
+> lawyer hat on.
+
+I'm puzzled that you don't understand. It seems quite
+obvious: If somebody writes Predicate => F(Cur_Inst), and the body of F loops
+through a million array elements, and checks whether each one is a prime number, that's
+going to take a long time, and there's nothing the language designer or compiler writer
+can or should do about it.
+
+It just means that you might want to turn off Predicates and other assertions, while
+keeping constraint checks turned on.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 3:07 PM
+
+> I don't see any "cavalier attitude". It's simply a fact that
+> predicates can be arbitrarily slow, whereas constraints are restricted
+> to simple (and therefore efficient) checks.
+>
+> A fact isn't an "attitude", cavalier or otherwise.
+
+Ah, OK, I thought you were saying that the implementation could be arbitrarily
+slow, yes of course I understadn you can write inefficient predicate checks.
+
+
+> I'm puzzled that you don't understand. It seems quite
+> obvious: If somebody writes Predicate => F(Cur_Inst), and the body
+> of F loops through a million array elements, and checks whether each
+> one is a prime number, that's going to take a long time, and there's
+> nothing the language designer or compiler writer can or should do
+> about it.
+
+I thought you were saying something completely different so now that I
+understand I agree.
+
+> It just means that you might want to turn off Predicates and other
+> assertions, while keeping constraint checks
+
+OK, I see what you are saying (indeed constraint checks vs assertion checks in the gnat
+front end is similar to this).
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 4:22 PM
+
+> Ah, OK, I thought you were saying that the implementation could be
+> arbitrarily slow, ...
+
+Ah, now I understand the misunderstanding.
+Glad that's cleared up -- I was pretty mystified by your earlier message!
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 4:37 PM
+
+Funny sometimes how two people talk past one another and neither can understand
+the idiotic position of the other, and it is all just a misunderstanding.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 2:31 PM
+
+> The reason invariants are so different from constraints is the
+> inside/outside semantics, so they can be very deliberately "violated"
+> and nothing is wrong. Programmers DO need to understand this
+> distinction!
+
+Agreed (that programmers need to understand this).
+
+Predicates can be temporarily and deliberately violated too, by a different
+mechanism: Use the 'Base attribute. Only works for scalars, unfortunately.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 3:04 PM
+
+> Predicates can be temporarily and deliberately violated too, by a
+> different
+> mechanism: Use the 'Base attribute. Only works for scalars, unfortunately.
+
+I don't see that as a way of violating the predicate, what do you have in mind (and
+how is it different from the situation with constraints).
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Friday, October 15, 2010 3:23 PM
+
+...
+> Assertions (including predicates) are not checks, so 11.6 does not
+> apply to them, according to the current proposal.
+
+Like Robert, I don't view predicates as assertions; I think that is a lousy model. I
+personally don't think of any of the others as assertions, either. Tying them to the
+assertion mechanism was a matter of expediency (don't have to have a separate
+mechanism for turning them on and off) more than one of intent.
+
+If/when these ever get implemented in Janus/Ada, they'll come with a real global
+in/global out mechanism, and there'll be warnings if it is violated.
+(Possibly even errors unless in what GNAT calls "pedantic" mode.)
+
+In another message, Bob says:
+...
+>You want me to say, "Pre => Kind(N) in (N_Record_Definition | N_Variant)"
+>but that's no safer -- no language rule prevents Kind from modifying
+globals or components.
+
+No, I don't *want* to you to write this at all - not in Pre, Post, Invariant,
+Predicate, or anything else that gets invented - not without proper, checked
+contracts on Kind. You can write it in Assert pragmas if you want, anything goes
+there.
+
+The Ada language doesn't have the tools to enforce that, so it can't be a
+language rule. Unfortunately. But that doesn't mean that you should write
+dangerous things just because you can.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 3:40 PM
+
+> If/when these ever get implemented in Janus/Ada, they'll come with a
+> real global in/global out mechanism, and there'll be warnings if it is
+> violated. (Possibly even errors unless in what GNAT calls "pedantic" mode.)
+
+Don't get confused --pedantic means "folow the standard even if it is silly", it
+does not mean be more strict than the standard (just a terminology issue, but if
+we start using pedantic other than in the well known gcc sense, we will confuse
+ourselves).
+
+> In another message, Bob says:
+> ...
+>> You want me to say, "Pre => Kind(N) in (N_Record_Definition | N_Variant)"
+>> but that's no safer -- no language rule prevents Kind from modifying
+> globals or components.
+>
+> No, I don't *want* to you to write this at all - not in Pre, Post,
+> Invariant, Predicate, or anything else that gets invented - not
+> without proper, checked contracts on Kind. You can write it in Assert
+> pragmas if you want, anything goes there.
+
+This is absurd to me. It is a perfect use of predicates, and the use of assertions
+wouldn't work at all, because we need the checks to be everywhere, and the whole
+point is NOT to scatter assertions around the place.
+
+> The Ada language doesn't have the tools to enforce that, so it can't
+> be a language rule. Unfortunately. But that doesn't mean that you
+> should write dangerous things just because you can.
+
+What Bob proposes is not dangerous at all, it is just adding automated checking
+to rules that now exist only in comments. If you don't undertstand this, then you
+just have a wrong model in your head of what Bob proposes.
+
+There is nothing dangerous about checking something which is now not checked at
+all. It's not checked at all now, because it's not practical syntactically to do
+it with assertions. Now with predicates we can do the checks in the places where
+they will be helpful with a minimal syntactic overhead. This will be potentially
+useful in detecting coding errors that might otherwise escape early detection.
+
+If your coding philosophy says we shouldn't be doing this, I haven't the foggiest
+idea why you think that, and frankly don't care much, but I AM sure you should not
+be trying to impose these peculiar ideas on other programmers :-)
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 4:10 PM
+
+> I don't see that as a way of violating the predicate, what do you have
+> in mind
+
+Using the silly Even subtype:
+
+ procedure Q(X: in out Even) is
+
+ procedure P(X: in out S'Base) is ... end;
+ begin
+ ... Here X is even.
+ declare
+ Y : S'Base := X + 1;
+ -- Y is not even.
+ begin
+ Y := Y + 1;
+ -- Now Y is even again, so we can safely assign it back to X.
+ X := Y;
+ end;
+
+ -- Or we could call a procedure:
+ P(X); -- P can make X odd, but restores its evenness
+ before returning.
+ end Q;
+
+This isn't a big deal. I'm just saying that (for scalars) the programmer has
+full control of when the predicate applies and when it doesn't.
+
+>... (and how is it different from the situation with constraints).
+
+It's not different for constraints. I'm trying to design predicates to be as
+similar as possible to constraints (but no more so ;-)).
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 4:32 PM
+
+>> I don't see that as a way of violating the predicate, what do you
+>> have in mind
+
+This doesn't even vaguely violate the predicate as far as I am concerned, you
+have two subtypes S and S'Base, one has a predicate the other doesn't. You can
+assign between them, but if you assign from S'Base to S, the predicate is
+checked. This is nothing like having a value *of the subtype with the invariant*
+having a value that does not meet the invariant inside the abstraction.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 4:40 PM
+
+> ...
+> > Assertions (including predicates) are not checks, so 11.6 does not
+> > apply to them, according to the current proposal.
+>
+> Like Robert, I don't view predicates as assertions; I think that is a
+> lousy model. I personally don't think of any of the others as assertions, either.
+
+Saying "a predicate is an assertion" is not a "model". It's just a term.
+A rose by any other name...
+
+> Tying them to the assertion mechanism was a matter of expediency
+> (don't have to have a separate mechanism for turning them on and off)
+> more than one of intent.
+
+For what it's worth, Bertrand Meyer, who should be considered an authority in
+this area for obvious reasons, uses the term "assertion" to apply to
+pre/postconditions, and to invariants, and to whatever the Eiffel equivalent of
+pragma Assert is. At least, that's my memory -- I'm too lazy to look it up and
+verify that statement.
+
+Note that I've been using the term "assertion" inconsistently.
+With my programmer hat on, "assertion" usually includes "constraint".
+With my language lawyer hat on, it usually/sometimes does not.
+Sorry about that. ;-)
+
+Eiffel doesn't have constraints. Meyer recently invented something like
+null_exclusions.
+
+> If/when these ever get implemented in Janus/Ada, they'll come with a
+> real global in/global out mechanism, and there'll be warnings if it is violated.
+
+Sounds good to me!
+
+****************************************************************
+
+From: Rnady Brukardt
+Date: Friday, October 15, 2010 4:41 PM
+
+> > If/when these ever get implemented in Janus/Ada, they'll come with a
+> > real global in/global out mechanism, and there'll be warnings if it
+> > is violated.
+> > (Possibly even errors unless in what GNAT calls "pedantic" mode.)
+>
+> Don't get confused --pedantic means "folow the standard even if it is
+> silly", it does not mean be more strict than the standard (just a
+> terminology issue, but if we start using pedantic other than in the
+> well known gcc sense, we will confuse ourselves).
+
+I think I used it correctly. If in "pedantic" mode, the language rules would be
+followed exactly (in this case, allowing dangerous function calls). If not in
+"pedantic" mode, warnings or even errors would be produced for dangerous
+function calls in these contexts.
+
+...
+> > The Ada language doesn't have the tools to enforce that, so it can't
+> > be a language rule. Unfortunately. But that doesn't mean that you
+> > should write dangerous things just because you can.
+>
+> What Bob proposes is not
+> dangerous at all, it is just adding automated checking to rules that
+> now exist only in comments. If you don't undertstand this, then you
+> just have a wrong model in your head of what Bob proposes.
+
+It's dangerous because any function call is dangerous in these contexts unless
+it is declared and checked to not have conflicting side-effects. I don't *want*
+people to write dangerous code -- period. Now, there isn't going to be any way
+to stop someone from writing such code, but that doesn't mean that you should
+do so.
+
+> If your coding philosophy says we shouldn't be doing this, I haven't
+> the foggiest idea why you think that, and frankly don't care much, but
+> I AM sure you should not be trying to impose these peculiar ideas on
+> other programmers :-)
+
+We've had this discussion before. Predicates, preconditions, et. al. should
+only contain "pure" functions (for some reasonable definition of "pure",
+admittedly hard to do). Anything else is dangerous because it doesn't meet the
+expectations of the use. To take a concrete example, using the Is_Valid
+function of Claw in a predicate or precondition is dangerous because it can
+change values because of some user action that is asynchronous in relation to
+the executing code. Just because the precondition or predicate succeeds tells
+you nothing about the current state of the object - and this leads to dangerous
+assumptions in the code (that you don't have to worry about Not_Valid_Error
+exceptions being raised).
+
+I believe that there is an obligation of the compiler to reduce/eliminate the
+creation of dangerous predicates/preconditions. This can only be done if the
+contract of functions includes some sort of enforced side-effect information,
+so it isn't possible to do it in Ada 2012 as proposed -- but this does not mean
+that it shouldn't be done.
+
+I know that we totally disagree on what and how dangerous side-effect in
+functions are identified (yours is operational and thus cannot be enforced;
+mine is functional and can be enforced) -- I think everything else flows from
+that. We can only agree to disagree on this topic.
+
+Anyway, this isn't going to be a language rule in any case, so it's probably
+irrevelant to this group.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 5:25 PM
+
+> I think I used it correctly. If in "pedantic" mode, the language rules
+> would be followed exactly (in this case, allowing dangerous function
+> calls). If not in "pedantic" mode, warnings or even errors would be
+> produced for dangerous function calls in these contexts.
+
+OK, right!
+
+> It's dangerous because any function call is dangerous in these
+> contexts unless it is declared and checked to not have conflicting
+> side-effects. I don't *want* people to write dangerous code -- period.
+> Now, there isn't going to be any way to stop someone from writing such
+> code, but that doesn't mean that you should do so.
+
+Well I think this is a legitimate point of view, but NOT one that should
+influecne the language design much, and certainly we don't want to insist on
+others following this point of view (with which i strongly disagree). The
+language should only to a certain extent enforce particular styles. By trying
+to outlaw dangersous stuff, you will almost always outlaw useful stuff as
+well, and thus decrease safety of some programs.
+
+>> If your coding philosophy says we shouldn't be doing this, I haven't
+>> the foggiest idea why you think that, and frankly don't care much,
+>> but I AM sure you should not be trying to impose these peculiar ideas
+>> on other programmers :-)
+>
+> We've had this discussion before. Predicates, preconditions, et. al.
+> should only contain "pure" functions (for some reasonable definition
+> of "pure", admittedly hard to do). Anything else is dangerous because
+> it doesn't meet the expectations of the use. To take a concrete
+> example, using the Is_Valid function of Claw in a predicate or
+> precondition is dangerous because it can change values because of some
+> user action that is asychronous in relation to the executing code.
+> Just because the precondition or predicate succeeds tells you nothing
+> about the current state of the object - and this leads to dangerous
+> assumptions in the code (that you don't have to worry about Not_Valid_Error
+> exceptions being raised).
+
+That's fine, but any attempt to define exactly what you mean by pure here and
+to outlaw functions you don't think are pure is misguided, and will most
+certainly result in forbidding useless stuff.
+
+> I believe that there is an obligation of the compiler to
+> reduce/eliminate the creation of dangerous predicates/preconditions.
+> This can only be done if the contract of functions includes some sort
+> of enforced side-effect information, so it isn't possible to do it in
+> Ada 2012 as proposed -- but this does not meant that it shouldn't be done.
+
+I disagree with pursuing this idea, I think it will be a big mistake to try
+to do anything in the language in this direction.
+
+> I know that we totally disagree on what and how dangerous side-effect
+> in functions are identified (yours is operational and thus cannot be
+> enforced; mine is function and can be enforced) -- I think everything
+> else flows from that. We can only agree to disagree on this topic.
+
+The issue is not whether to agree with your view or my view on this, the issue
+is whether the language should try to enforce one viewpoint. To me the ONLY
+useful definition of pure is operational (e.g. a counter kept to count calls
+for performance reasons does not make a function impure, and any function is
+impure given it takes time to execute at one extreme point of view). Any
+language feature will be a menace. We discussed this at great lengths in the
+Ada 83 design, several people wanted functions to be required to be pure, but
+were eventually convinced that the attempt was misguided (by hundreds of
+examples).
+
+> Anyway, this isn't going to be a language rule in any case, so it's
+> probably irrevelant to this group.
+
+One language thing that would be useful is what gnat calls pragma Pure_Function
+to label (and check) individual functions for being pure in the sense of
+functions in a pure unit.
+
+Then if you want the restricted view, it is easier for a programmer to achieve
+that.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Friday, October 15, 2010 5:39 PM
+
+...
+> One language thing that would be useful is what gnat calls pragma
+> Pure_Function to label (and check) individual functions for being pure
+> in the sense of functions in a pure unit.
+>
+> Then if you want the restricted view, it is easier for a programmer to
+> achieve that.
+
+We seriously considered that pragma for Ada 2005 (see AI95-00290-1), but we
+couldn't get consensus on how it should work. There was a significant
+contingent that felt that labeling something Pure means that it should be
+enforced as it is for pure packages (else there is a confusion). In the end,
+we decided that changing the definition of a pragma from a commonly used
+implementation was a bad idea, and there didn't seem to be another name that
+made sense. So the idea was dropped.
+
+One of the reasons that I pursued global in/global out annotations was to get
+this functionality in a way that wouldn't conflict with existing
+implementations. But it was considered too immature (a statement that I can't
+disagree with). So we have nothing this go-round.
+
+****************************************************************
+
+From: Robert Dewar
+Date: Friday, October 15, 2010 6:47 PM
+
+> We seriously considered that pragma for Ada 2005 (see AI95-00290-1),
+> but we couldn't get consensus on how it should work. There was a
+> significant contingent that felt that labeling something Pure means
+> that it should be enforced as it is for pure packages (else there is a
+> confusion). In the end, we decided that changing the definition of a
+> pragma from a commonly used implementation was a bad idea, and there
+> didn't seem to be another name that made sense. So the idea was dropped.
+
+Too bad that the "it must enforce our theoretical notion of X or we won't
+tolerate it at all" school was allowed to derail this useful feature. Never
+mind, all Ada 2005 users in the real world do have access to this useful
+pragma. And a style rule that all functions in predicates and variants have
+to be pure at least in this sense is probably a useful style rule.
+
+****************************************************************
+
+From: Bob Duff
+Date: Friday, October 15, 2010 5:26 PM
+
+> It's dangerous because any function call is dangerous in these
+> contexts unless it is declared and checked to not have conflicting side-effects.
+
+"Dangerous" means "potentially harmful", so I think it's fair to use "dangerous"
+here -- the Kind function might read the clock and do crazy things based on that.
+
+But there are degrees of "danger". If I happen to know that Kind doesn't read
+the clock (etc), then it's really not very dangerous.
+
+I guess my most important point in all this discussion is:
+Consider the alternatives. Their relative danger. I mean, comments are dangerous.
+"-- This thing is never zero." is not checked by the compiler (of course!). It
+might lead someone to divide by that thing. But I don't want to outlaw comments
+just in case they might be false.
+
+****************************************************************
+
+From: Yannick Moy
+Date: Monday, October 18, 2010 3:51 AM
+
+Plus we can build tools (different from the compiler) which analyze your
+pre/post/predicate aspects and issue errors/warnings, while we will never be
+able to do so for comments. Including warnings that there are writes to some
+data.
+
+****************************************************************
Questions? Ask the ACAA Technical Agent