CVS difference for ai12s/ai12-0377-1.txt

Differences between 1.4 and version 1.5
Log of other versions for file 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