CVS difference for ai12s/ai12-0377-1.txt
--- ai12s/ai12-0377-1.txt 2020/05/02 03:43:14 1.4
+++ ai12s/ai12-0377-1.txt 2020/05/16 05:44:19 1.5
@@ -225,3 +225,598 @@
I suspect that the AI and especially the wording will need some wordsmithing.
****************************************************************
+
+[Editor's note: Some of the e-mails in the following thread discussed topics
+in both this AI and AI12-0378-1. The e-mails were split and filed in the
+appropriate AI to avoid confusion.]
+
+From: Tucker Taft
+Sent: Wednesday, April 29, 2020 11:34 AM
+
+Wording suggestion:
+
+If the mode is out, the actual parameter is a view conversion, and the type
+of the formal parameter is a scalar type, then either:
+
+ * the target and operand type do not have the Default_Value aspect
+ specified; or
+
+ * the target and operand type both have the Default_Value aspect
+ specified, and there shall exist a type (other than a root numeric
+ type) that is an ancestor of both the target type and the operand type.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Wednesday, April 29, 2020 3:32 PM
+
+BTW, Claire, if you could provide an example of the problem that you were
+concerned about with the AI12-0377-1 proposal, it would be appreciated.
+
+My incomplete understanding of your concern made it appear that the only
+solution would be to ban all view conversions of types with Default_Value
+unless the defaults were the same. That would prevent declaring (or at
+least using) any derived types with different defaults (if there are
+primitive operations) -- but that was specifically the case that Arno wanted
+us to allow as he has customer code that depends upon it. It doesn't seem
+possible to thread that needle!
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Wednesday, April 29, 2020 4:57 PM
+
+> If the mode is out, the actual parameter is a view conversion, and
+> the type of
+> the formal parameter is a scalar type, then either:
+>
+> * the target and operand type do not have the Default_Value aspect
+> specified; or
+
+I doubt that a Float and a Boolean, both without a Default_Value, are o.k.
+in a view conversion :-) (There is a convertability constraint missing).
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Wednesday, April 29, 2020 5:18 PM
+
+...
+>> If the mode is out, the actual parameter is a view conversion, and
+>> the type of
+>> the formal parameter is a scalar type, then either:
+>>
+>> * the target and operand type do not have the Default_Value aspect
+>> specified; or
+>
+> I doubt that a Float and a Boolean, both without a Default_Value, are
+> o.k. in a view conversion :-) (There is a convertability constraint
+> missing).
+
+This is the dynamic semantics. The legality rules have already done their
+thing, so we only need to explain what happens with legal view conversions.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Thursday, April 30, 2020 8:46 AM
+
+>> I doubt that a Float and a Boolean, both without a Default_Value, are
+>> o.k. in a view conversion :-) (There is a convertability constraint
+>> missing).
+>>
+> This is the dynamic semantics. The legality rules have already done their
+> thing, so we only need to explain what happens with legal view conversions.
+>
+
+o.k. Understood. Or maybe only half of it, because the next bullet
+
+> * the target and operand type both have the Default_Value aspect
+> specified, and there shall exist a type (other than a root numeric
+> type) that is an ancestor of both the target type and the operand type.
+
+includes a compatibility constraint as well, which ought to have been checked
+by static semantics as well. (That part of the wording triggered my comment in
+the first place, a "why here, but not there?"-question).
+
+****************************************************************
+
+From: Claire Dross
+Sent: Thursday, April 30, 2020 3:28 AM
+
+Honestly, I think I will need some help to understand the rationale of the
+rules for passing of OUT parameters with default values. Yesterday, we said
+that we did not want a null procedure to deinitialize a scalar variable whose
+type has a Default_Value aspect. But I don't really understand why. Surely
+null procedures will deinitialize variables which don't have this aspect, and
+this is a bounded error, right? So to say it otherwise, I think
+
+ procedure P (X : out T) is
+ begin
+ null;
+ end P;
+
+where T is an integer type without a Default_Value is wrong. Why should we do
+anything to support correctly (reject correctly) the corner case of call to
+such a function on a view conversion?
+
+****************************************************************
+
+From: Jeff Cousins
+Sent: Thursday, April 30, 2020 3:57 AM
+
+To be honest, I agree with Claire. To not assign anything to an out parameter
+is plain wrong so I don't see why we should go to a lot of trouble to get it
+to return something sensible in certain circumstances. (A former colleague
+used somewhat stronger language).
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, April 30, 2020 8:08 AM
+
+One of the fundamental "promises" associated with types with a default, is
+they never become de-initialized.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Thursday, April 30, 2020 8:28 AM
+
+To me, the foremost reason in favor of the AI is that I would like to rely on
+the fact that any variable with specified default_value is guaranteed to
+always be initialized. No buts, ifs, and whens, or special cases or corners
+that I need to check for after all.
+
+Just like non-null types .... no buts, ifs, except whens....
+
+And as to risk: a deinitialized Integer is almost as bad as a deinitialized
+access value. All I need to do is use it as index into an array, where
+matching subtype properties are statically established and hence the index
+check unnecessary. (I can even exploit that security hole by placing the
+"right value" into place by a preceeding call.)
+
+****************************************************************
+
+From: Claire Dross
+Sent: Thursday, April 30, 2020 8:51 AM
+
+> To me, the foremost reason in favor of the AI is that I would like to
+> rely on the fact that any variable with specified default_value is
+> guaranteed to always be initialized. No buts, ifs, and whens, or special
+> cases or corners that I need to check for after all.
+
+But do we achieve that by the above?
+Here is an example:
+
+procedure Test_Out_Param with SPARK_Mode is
+ type My_Neg is new Integer range Integer'First .. -1 with
+ Default_Value => -1;
+ type My_Pos is new Integer range 1 .. Integer'Last with
+ Default_Value => 1;
+
+ procedure P (X : out My_Neg) is
+ begin
+ null;
+ end P;
+
+ Y : My_Pos;
+begin
+ P (My_Neg (Y));
+end Test_Out_Param;
+
+With the change proposed in this AI, I get that after a call to P, Y
+indeed is still properly initialized. But what about inside P? Certainly
+X is not in the bounds of My_Neg, and the fact that its initial value is set
+by the default of some other type or not does not change anything about
+that...
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, April 30, 2020 9:04 AM
+
+Being initialized, but out of range, and having a random uninitialized value,
+are two different things. A compiler cannot assume an OUT parameter is
+initialized to an in-range value. But if it has a default, it can assume it
+is not a random bit pattern, so a constraint check, for example, will have a
+well-defined result.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Thursday, April 30, 2020 9:20 AM
+
+> To me, the foremost reason in favor of the AI is that I would like to
+> rely on the fact that any variable with specified default_value is
+> guaranteed to always be initialized. No buts, ifs, and whens, or
+> special cases or corners that I need to check for after all.
+>
+> Just like non-null types .... no buts, ifs, except whens....
+
+Right, that's the property this AI is trying to preserve.
+
+> And as to risk: a deinitialized Integer is almost as bad as a
+> deinitialized access value. All I need to do is use it as index into
+> an array, where matching subtype properties are statically established
+> and hence the index check unnecessary. (I can even exploit that
+> security hole by placing the "right value" into place by a preceeding
+> call.)
+
+True in Ada 83, but now it's a bounded error, so "A(I) := ..."
+must either modify some element of A, or raise an exception if I is invalid.
+
+****************************************************************
+
+From: Claire Dross
+Sent: Thursday, April 30, 2020 9:22 AM
+
+> Being initialized, but out of range, and having a random uninitialized
+> value, are two different things. A compiler cannot assume an OUT parameter
+> is initialized to an in-range value. But if it has a default, it can
+> assume it is not a random bit pattern, so a constraint check, for example,
+> will have a well-defined result.
+
+I must say the difference on integer types does not seem obvious to me. And
+the problem raised by Erhard seems to still occur?
+
+****************************************************************
+
+From: Bob Duff
+Sent: Thursday, April 30, 2020 11:49 AM
+
+> I must say the difference on integer types does not seem obvious to
+> me. And the problem raised by Erhard seems to still occur?
+
+No, adding to your earlier example:
+
+procedure Test_Out_Param with SPARK_Mode is
+ type My_Neg is new Integer range Integer'First .. -1 with
+ Default_Value => -1;
+ type My_Pos is new Integer range 1 .. Integer'Last with
+ Default_Value => 1;
+
+ A : array (My_Neg range -1 .. -1) of Integer := (others => 0);
+
+ procedure P (X : out My_Neg) is
+ begin
+ A (X) := 123; -- Constraint_Error raised here.
+ end P;
+
+ Y : My_Pos;
+begin
+ P (My_Neg (Y));
+end Test_Out_Param;
+
+The above is required to raise C_E rather than trash some memory location.
+GNAT does that correctly (at least for this example).
+
+The compiler is not allowed to eliminate checks based purely on the subtype's
+range -- it must also prove that the value is valid. This was an Ada 95
+change.
+
+****************************************************************
+
+From: Bob Duff
+Sent: Thursday, April 30, 2020 11:53 AM
+
+Here's another variation on that example:
+
+procedure Test_Out_Param with SPARK_Mode is
+ type My_Neg is new Integer range Integer'First .. -1 with
+ Default_Value => -1;
+ type My_Pos is new Integer range 1 .. Integer'Last with
+ Default_Value => 1;
+
+ procedure P (X : out My_Neg) is
+ begin
+ X := -1;
+ end P;
+
+ Y : My_Pos;
+begin
+ P (My_Neg (Y)); -- Constraint_Error raised on copy back.
+end Test_Out_Param;
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, April 30, 2020 2:02 PM
+
+>Just like non-null types .... no buts, ifs, except whens....
+
+Actually, there is one "but" with null exclusions, one that I noticed working
+on this AI:
+
+ Ptr : Some_Ptr := null;
+
+ procedure P (A : out not null Some_Ptr) is
+ -- Can't assume that A is not null here.
+ end P;
+
+ P (Ptr);
+
+A null exclusion on an out parameter cannot be assumed to be true, since there
+is no way to initialize it with a non-null value if the actual is in fact null
+(as in this example). We surely don't want to be conjuring a junk object out
+of the ether just so we can pass it on the possible chance that someone might
+read it. And we don't want to be raising exceptions for passing a value that
+probably never will be used.
+
+Which probably goes to show that there is no rule that has no exceptions. :-)
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, April 30, 2020 2:16 PM
+
+For OUT parameters, you generally have to assume the constraints are *not*
+satisfied on the way in. The point about having a default value, as do all
+access objects, is that you can presume it has a *well defined* value. The
+constraints on an "out" parameter are checked only on the way "out" so you
+should interpret an out parameter as always being a completely unconstrained
+object initially, that has some constraints you had better satisfy before you
+do a return.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, April 30, 2020 2:45 PM
+
+Right. But that means that whatever you can assume about every other object
+in an Ada program does not apply to "out" parameters. (with the exception of
+the tag and accessibility checks that would be impossible to properly check
+on a usage, the focus of AI12-0378-1, the split from AI12-0377-1 as requested
+yesterday). My point to Erhard's statement is that there is always a "but"
+when it comes to "out" parameters.
+
+****************************************************************
+
+From: Richard Wai
+Sent: Thursday, April 30, 2020 2:59 PM
+
+I always saw such null excluded out parameters as expressing a contract on
+the subprogram. So a null exclusion on an “out” parameter is a contract which
+states that the subprogram promises to set the parameter to something not null.
+Similarly if you had an out parameter of some constrained subtype, that’s a
+contract on the subprogram to produce a value of that subtype.
+
+I don’t see anything wrong with this:
+
+Type Day is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
+
+Subtype Workday is Day range Monday .. Friday;
+
+Procedure Next_Meeting (On_Day: out Workday);
+
+My_Busy_Day: Day := Saturday;
+
+Next_Meeting (My_Busy_Day);
+
+The contract is that Next_Meeting should only give me a Workday. But I
+shouldn’t be stopped from using a parameter of Day, especially if it is not
+already set to a value in the range of Workday..
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Friday, May 1, 2020 8:10 AM
+
+Interesting .... but maybe there was a bug in the example? The semantics
+that you describe seems too be "in out" semantics.
+
+See -- for inserts and remarks ...
+
+>> I must say the difference on integer types does not seem obvious to
+>> me. And the problem raised by Erhard seems to still occur?
+>
+> No, adding to your earlier example:
+>
+> procedure Test_Out_Param with SPARK_Mode is
+> type My_Neg is new Integer range Integer'First .. -1 with
+> Default_Value => -1;
+> type My_Pos is new Integer range 1 .. Integer'Last with
+> Default_Value => 1;
+>
+> A : array (My_Neg range -1 .. -1) of Integer := (others => 0);
+
+-- added another array
+ B : array (My_Pos range 1 .. 1) of Integer := (others => 0);
+>
+> procedure P (X : out My_Neg) is
+> begin
+> A (X) := 123; -- Constraint_Error raised here.
+
+-- I would have expected that the Default_Value -1 applies and A(-1)
+-- is perfectly fine, but
+ B (X) := 123; -- has to raise Constraint_Error for B(-1)
+
+> end P;
+>
+> Y : My_Pos;
+> begin
+> P (My_Neg (Y));
+
+-- has to raise Constraint_Error on the way out, when X (=-1) gets
+-- written to Y per copy semantics for scalars
+
+> end Test_Out_Param;
+
+****************************************************************
+
+From: Bob Duff
+Sent: Friday, May 1, 2020 10:28 AM
+
+> Interesting .... but maybe there was a bug in the example? The
+> semantics that you describe seems too be "in out" semantics.
+
+Right, 'out' parameters sometimes pass information IN, which is strange.
+
+> > A (X) := 123; -- Constraint_Error raised here.
+>
+> -- I would have expected that the Default_Value -1 applies and A(-1)
+> -- is perfectly fine, but
+
+That's not an unreasonable expectation, but I guess that's not what language
+designers decided. The goal was "if it has a default, it can't get
+deinitialized", and never mind if the default is outside the bounds of the
+subtype, as we see in these weird 'out' param cases.
+
+> B (X) := 123; -- has to raise Constraint_Error for B(-1)
+>
+> > end P;
+> >
+> > Y : My_Pos;
+> > begin
+> > P (My_Neg (Y));
+>
+> -- has to raise Constraint_Error on the way out, when X (=-1) gets
+> -- written to Y per copy semantics for scalars
+
+If it were assigned to -1 inside the procedure, then it would raise C_E on copy
+back. But if it's not assigned at all (which is a weird thing to do), then it
+remains +1, which copies back without C_E.
+
+Not sure I would have designed it that way...
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Friday, May 1, 2020 11:16 AM
+
+> Right, 'out' parameters sometimes pass information IN, which is
+> strange.
+
+Well, yes, sometimes, but not the value in the scalar case with copy
+semantics. My reading of the Manual says that the value is uninitialized
+in the absence of Default_Value (8.6.1 (15)), or initialized to a specfified
+Default_Value (8.6.1.(13)). There is no third case. In consequence, the final
+value is just that if X is not assigned to in the body.
+
+So, your expectation that "1" from Y arrives at X is not justified by
+anything in the manual, or is it? And, if the actual value were always passed
+in, the Default_Value on out parameters would never engage and hence be
+utterly useless.
+
+It may be strange that it always engages for scalar outs, but I much prefer
+that to deinitialized variables despite an assertion to the contrary.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Friday, May 1, 2020 12:29 PM
+
+>> Right, 'out' parameters sometimes pass information IN, which is
+>> strange.
+
+>Well, yes, sometimes, but not the value in the scalar case with copy
+>semantics.
+>My reading of the Manual says that the value is uninitialized in the
+>absence of Default_Value (8.6.1 (15)),
+
+You mean 6.4.1(15).
+
+>or initialized to a specfified
+>Default_Value (8.6.1.(13)).
+
+6.4.1(13) is about access types (and is one the the rules we need to change
+slightly).
+
+6.4.1(13.1/4) is about types with Default_Value and it does not say that.
+It says the value of the actual is passed it without any check. That's the
+semantics that Ichbiah picked for out parameters like access and composites.
+
+I suppose we *could* have done something different regardless (it was a
+totally new feature), but it's getting rather late to change basic semantics
+of an Ada 2012 feature. Especially to silently change the semantics of
+existing, legal code -- that's the worst kind of incompatibility.
+
+>There is no third case. In consequence, the
+>final value is just that if X is not assigned to in the body.
+
+That's true, but you have dreamed up semantics that doesn't exist in the RM.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Friday, May 1, 2020 6:05 PM
+
+Sorry that I mistyped the references. I meant 6.4.1. in both cases.
+Here they are again in corrected form:
+
+My reading of the Manual says that the value is uninitialized in the absence
+of Default_Value (6.4.1 (15)), or initialized to ... (6.4.1.(13.1/4)).
+
+But you are right. I imagined semantics that never existed. I didn't even read
+the sentence to its conclusion because it was so obvious what the initial
+value would be. It is hard to believe that the semantics of Default_Value for
+out parameters are so misleading -- the type says that the default initial
+value is 1, and then means that the initial value is taken from the actual.
+
+Ok. Case closed for me, since the RM is consistent albeit very surprising.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Saturday, May 2, 2020 7:46 AM
+
+>To be honest, I agree with Claire. To not assign anything to an out
+>parameter is plain wrong so I don't see why we should go to a lot of trouble
+>to get it to return something sensible in certain circumstances. (A former
+>colleague used somewhat stronger language).
+
+I remember Bob Morgan used to say something like: "Just because it is
+erroneous doesn't mean we should generate code that deletes the disk."
+
+The fact is that most programs contain code whose execution might result in
+erroneous execution or produce a bounded error.
+
+We provide certain guarantees so that even though the code may be buggy, you
+know the consequences are limited. Ada's access types have always made the
+guarantee that an access value is never complete junk. When we introduced the
+Default_Value aspect, our goal was to make the same guarantee, namely that a
+value of a type with a Default_Value is never complete junk. You may believe
+that was a mistake, but we made it many years ago, and at this point, I think
+we should not withdraw that guarantee.
+
+We have discovered a corner case with view conversions. I don't think that
+means we should say: the guarantee holds except in certain corner cases. We
+should come up with a reasonable rule for this corner case.
+
+****************************************************************
+
+From: Tullio Vardanega
+Sent: Saturday, May 2, 2020 7:51 AM
+
+This is my view also. Not a view conversion, though.
+
+****************************************************************
+
+From: Claire Dross
+Sent: Monday, May 4, 2020 1:50 AM
+
+>I don’t see anything wrong with this:
+>
+>Type Day is (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday);
+>
+>Subtype Workday is Day range Monday .. Friday;
+>
+>Procedure Next_Meeting (On_Day: out Workday);
+>
+>My_Busy_Day: Day := Saturday;
+>
+>Next_Meeting (My_Busy_Day);
+>
+>The contract is that Next_Meeting should only give me a Workday. But I
+>shouldn’t be stopped from using a parameter of Day, especially if it is not
+>already set to a value in the range of Workday..
+
+What is more dubious is that nothing prevents me from not setting On_Day to a
+Workday in Next_Meeting, and so, even if day has a default value.
+
+****************************************************************
+
+From: Erhard Ploedereder
+Sent: Friday, May 1, 2020 8:10 AM
+
+****************************************************************
Questions? Ask the ACAA Technical Agent