CVS difference for ais/ai-00216.txt

Differences between 1.9 and version 1.10
Log of other versions for file ais/ai-00216.txt

--- ais/ai-00216.txt	2002/07/23 01:05:23	1.9
+++ ais/ai-00216.txt	2002/12/04 23:43:37	1.10
@@ -1,13 +1,13 @@
-!standard B.03.03      (00)                         02-07-11  AI95-00216/08
+!standard B.03.03      (00)                         02-12-02  AI95-00216/09
 !standard B.03         (60.2)
 !class amendment 99-03-23
-!status Amendment 200Y 02-07-11
+!status work item 02-11-06
 !status ARG Approved 6-0-3  02-06-22
 !status work item 99-03-23
 !status received 99-03-23
 !priority Medium
 !difficulty Hard
-!subject Unchecked Unions -- Variant Records With No Run-Time Discriminant
+!subject Unchecked unions -- variant records with no run-time discriminant
 
 !summary
 
@@ -67,7 +67,7 @@
 unchecked_union type must not be read.
 
 Constrained subtypes of an unchecked_union type are permitted, as this may be
-necessary to properly specify the (initial) discriminant value for a variable
+necessary to specify the (initial) discriminant value for a variable
 or subcomponent having the type. It is erroneous to perform any operation (in
 C or Ada) that would have failed a discriminant check had the discriminant been
 present at run-time.
@@ -75,7 +75,7 @@
 The pragma Unchecked_Union may be applied to a derived type, presuming it meets
 the requirements for the pragma. Converting the derived type to an
 unconstrained subtype of an ancestor (checked) type raises Program_Error,
-because there is no way to determine the values for the discriminants.
+because there is no way to determine the values of the discriminants.
 Converting to a constrained subtype is permitted, as the discriminant values
 are implied by the constraint (as above, the conversion is erroneous if it
 would have failed a discriminant check). Converting from an ancestor (checked)
@@ -108,7 +108,7 @@
 result.
 
 Record representation clauses are permitted for unchecked unions. No space is
-given for a discriminant; it is illgal to mention a discriminant explicitly in
+given for a discriminant; it is illegal to mention a discriminant explicitly in
 a component clause.
 
 An implementation may support this pragma for tagged record types or record
@@ -133,7 +133,7 @@
 
                 Syntax
 
-The form of pragma Unchecked_Union is as follows:
+The form of a pragma Unchecked_Union is as follows:
 
     pragma Unchecked_Union (first_subtype_local_name);
 
@@ -145,17 +145,17 @@
 The first_subtype_local_name of a pragma Unchecked_Union shall denote
 an unconstrained discriminated record subtype having a variant_part.
 
-The type is called an unchecked union type. A subtype of an
-unchecked union type is defined to have an unchecked union subtype.
-An object of an unchecked union type is defined to have an unchecked union
-object.
+A type to which a pragma Unchecked_Union applies is called an unchecked union
+type. A subtype of an unchecked union type is defined to be an unchecked
+union subtype. An object of an unchecked union type is defined to be an
+unchecked union object.
 
 All component subtypes of the type shall be C-compatible.
 
 If a component subtype of the type is subject to a per-object constraint,
 then the component subtype shall be an unchecked union subtype.
 
-Any name which denotes a discriminant of an object of an
+Any name that denotes a discriminant of an object of an
 unchecked union type shall occur within the declarative region of the type.
 
 A component declared in a variant_part of an unchecked union type shall not
@@ -166,7 +166,7 @@
 
 An unchecked union subtype shall not be passed as a generic actual parameter
 if the corresponding formal type has a known_discriminant_part or
-is a formal derived type which is not an unchecked union type.
+is a formal derived type that is not an unchecked union type.
 
                 Static Semantics
 
@@ -183,7 +183,7 @@
 A view of an unchecked union object [(including a type conversion or
 function call)] has "inferable discriminants" if it has a
 constrained nominal subtype, unless the object is a component of an
-enclosing unchecked union object which is subject to a per-object constraint
+enclosing unchecked union object that is subject to a per-object constraint
 and the enclosing object lacks inferable discriminants.
 
 An expression of an unchecked union type has "inferable
@@ -303,7 +303,7 @@
 
 @i<@s8<Syntax>>
 
-The form of pragma Unchecked_Union is as follows:
+The form of a pragma Unchecked_Union is as follows:
 
 @xindent<@b<pragma> Unchecked_Union (@i<first_subtype_local_>@fa<name>);>
 
@@ -314,9 +314,11 @@
 
 The @i<first_subtype_local_>@fa<name> of a @fa<pragma> Unchecked_Union shall
 denote an unconstrained discriminated record subtype having a @fa<variant_part>.
-The type called an @i<unchecked union type>. A subtype of an
-unchecked union type is defined to have an @i<unchecked union subtype>.
-An object of an unchecked union type is defined to have an @i<unchecked union
+
+A type to which a pragma Unchecked_Union applies is called an
+@i<unchecked union type>. A subtype of an
+unchecked union type is defined to br an @i<unchecked union subtype>.
+An object of an unchecked union type is defined to be an @i<unchecked union
 object>.
 
 All component subtypes of an unchecked union type shall be C-compatible.
@@ -324,7 +326,7 @@
 If a component subtype of an unchecked union type is subject to a per-object
 constraint, then the component subtype shall be an unchecked union subtype.
 
-Any name which denotes a discriminant of an object of an
+Any name that denotes a discriminant of an object of an
 unchecked union type shall occur within the declarative region of the type.
 
 A component declared in a @fa<variant_part> of an unchecked union type shall
@@ -335,7 +337,7 @@
 
 An unchecked union subtype shall not be passed as a generic actual parameter
 if the corresponding formal type has a @fa<known_discriminant_part> or
-is a formal derived type which is not an unchecked union type.
+is a formal derived type that is not an unchecked union type.
 
 @i<@s8<Static Semantics>>
 
@@ -352,7 +354,7 @@
 A view of an unchecked union object (including a type conversion or
 function call) has @i<inferable discriminants> if it has a
 constrained nominal subtype, unless the object is a component of an
-enclosing unchecked union object which is subject to a per-object constraint
+enclosing unchecked union object that is subject to a per-object constraint
 and the enclosing object lacks inferable discriminants.
 
 An expression of an unchecked union type has inferable discriminants if it is
@@ -388,8 +390,8 @@
 Randy Brukardt  99-03-29
 
 I've reformatted Tucker's submission into the format discussed at
-the recent ARG meeting. Note that I haven't made any of the changes
-considered at that meeting.
+the recent ARG meeting. (This is version /01). Note that I haven't made any
+of the changes considered at that meeting.
 
 *************************************************************
 
@@ -1022,6 +1024,1647 @@
 subcomponent.
 
 which may be easier to implement. But the first rule is what's required.
+
+*************************************************************
+
+From: Michael Yoder
+Sent: Thursday, October 31, 2002 at  3:39 PM
+
+This is a comment on AI-00216, Unchecked Unions.
+
+There's an issue that deserves at least some mention, namely, this would
+be the first Ada feature that directly breaks the ability to do precise
+garbage collection[1]. The ability could be preserved by adding this
+sentence:
+
+A component declared in a variant_part of an unchecked union type shall
+not be of an access type unless that type is one to which pragma
+Controlled applies explicitly or implicitly.
+
+Alternatively, it could be noted (as implementation advice?) that when
+such a component is present, and garbage collection is in use, it is
+generally necessary to use so-called "conservative" garbage collection
+techniques for areas of storage that might or might not represent access
+values.
+
+[1] I avoid the issue of whether using pragma Interface indirectly
+breaks this ability; I don't think it should automatically do so.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Thursday, October 31, 2002 at  5:00 PM
+
+<<There's an issue that deserves at least some mention, namely, this would
+be the first Ada feature that directly breaks the ability to do precise
+garbage collection[1]. The ability could be preserved by adding this
+sentence:>>
+
+First, of all, I wish we would not regard Unchecked_Union as a first class
+citizen when it comes to features. It is a low level kludge, designed to be
+used only to model C types (that is why incidentally I strongly oppose the
+efforts to generalize it unnecessarily, they will encourage people to think
+of it the way that is represented in the paragraph above, as a "feature"
+in Ada that breaks things).
+
+In fact the odd thing is that the claim above is completely wrong. It is
+absolutely clear that Unchecked_Conversion, and address overlays from the
+use of address clauses have exactly the same effect and of course I know
+that Michael knows this.
+
+So how could be make this statement? My guess is that the idea is that
+unchecked_conversion and address overlay are obviously low level junk
+stuff that would e.g. break garbage collection but Unchecked_Union is,
+for reasons that I cannot fathom, regarded as being a respectable
+feature in the language.
+
+<<A component declared in a variant_part of an unchecked union type shall
+not be of an access type unless that type is one to which pragma
+Controlled applies explicitly or implicitly.>>
+
+I object to this proposal, it has the effect of trying to elevate
+unchecked_union to a level of respectability that is unsuited to it.
+Unchecked_Union should be regarded as equivalent to the use of
+Unchecked_Conversion. Indeed it is basically syntactic sugar to make
+the use of unchecked conversion a little easier to use in this case.
+
+<<Alternatively, it could be noted (as implementation advice?) that when
+such a component is present, and garbage collection is in use, it is
+generally necessary to use so-called "conservative" garbage collection
+techniques for areas of storage that might or might not represent access>>
+
+But general address arithmetic (permitted in Ada, but not in C), can break
+even conservative garbage collection. For example, have a look at the
+implementation of the Tables unit in the GNAT sources. It provides a
+dynamic table facility using virtual origins for addressing using
+address arithmetic. Of course virtual origins break conservative
+garbage collection (because the virtual pointer is outside the
+allocated array block). Now of course the coding of Table is strictly
+speaking well into the implementation dependent/defined area, but in
+practice it is likely to work on most Ada implementations (and of course
+works fine in all GNAT implementations).
+
+Don't try to make Unchecked_Union into something it is not!
+
+*************************************************************
+
+From: Michael Yoder
+Sent: Thursday, October 31, 2002 at  6:19 PM
+
+>So how could be make this statement? My guess is that the idea is that
+>unchecked_conversion and address overlay are obviously low level junk
+>stuff that would e.g. break garbage collection but Unchecked_Union is,
+>for reasons that I cannot fathom, regarded as being a respectable
+>feature in the language.
+
+Wrong. Unchecked_Conversion, address clauses, and address arithmetic are
+just as respectable, as far as I'm concerned, as any non-deprecated
+feature of the language. They are different because, from the point of
+view of a garbage collector, it's perfectly feasible and reasonable to
+ignore their existence when collecting[1]: uses that break garbage
+collection are erroneous, or at least nonportable. With unchecked
+unions, the null treatment is a wrong choice, absent some guidance. The
+goal of the suggestion was to provide the guidance.
+
+Think before you condescend!
+
+[1] An implementation might need to mark variables with address clauses
+as immovable.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Thursday, October 31, 2002 at  7:30 PM
+
+But any program you write with unchecked unions can be easily transcribed
+to use unchecked conversion, the transformation is quite straightforward.
+All you do is to define an array of storage elements, and then whenever
+you access it, you unchecked convert to the record form you want before
+extracting the field you want.
+
+The only point of unchecked union is to make this procedure (a very familiar
+one for modeling C unions in the absence of this feature) a little more
+convenient, and also to ensure that things are layed out to match the
+C layout.
+
+So I am not "condescending" here, simply pointing out this obvious equivalence
+and suggesting that anything that breaks this equivalence is unwise and
+unwelcome. If it is OK to ignore unchecked conversion that is exactly
+equivalent to unchecked union then it is OK to ignore unchecked union.
+
+Mind you I think worrying about garbage collection is (to use the French
+phrase) a "storm in a glass". I think the likelihood of anyone trying to
+do garbage collection in a full blown Ada compiler is nil.
+
+Furthermore, speaking as someone with a lot of experience in garbage
+collected languages (from my SPITBOL and SETL days), I find the idea of
+garbage collection in the presence of low level features that can mess
+up memory to be pretty frightening. What can happen in such a situation
+is that memory gets slightly messed up by the first GC, then the cancer
+spreads until finally things totally collapse N GC's later, by which
+time it is really hard to figure out what is going on :-)
+
+*************************************************************
+
+From: Michael Yoder
+Sent: Thursday, October 31, 2002 at 10:35 PM
+
+>  I think the likelihood of anyone trying to
+>do garbage collection in a full blown Ada compiler is nil.
+
+Well, the IAPC compiler (for Ada83) had run-time garbage collection, and
+I was personally involved in implementing it (including the garbage
+collection part). Mind you I'm not claiming this should really count: it
+was only a prototype, though it did implement the full language.
+
+I'm surprised at the seeming implication that your mixed Ada/Java
+product doesn't garbage collect. Would you be willing to expand on that?
+
+>Furthermore, speaking as someone with a lot of experience in garbage
+>collected languages (from my SPITBOL and SETL days), I find the idea of
+>garbage collection in the presence of low level features that can mess
+>up memory to be pretty frightening.
+
+Well... I did simple low-level stuff involving address operations in UCI
+Lisp, which had a relocating collector. Maybe if you've gotten away with
+it it's less frightening. :-) I won't pretend that getting away with it
+once or twice is significant empirical evidence against your viewpoint.
+But my take on mixing the two would be to use a different approach in
+any case: you need a heap that is protected from garbage collection, for
+pragma Controlled. I'd restrict address calculations, barring odd
+emergencies, to uses involving entities in that heap or, perhaps, in
+task stacks.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Thursday, October 31, 2002 at 10:41 PM
+
+Well the tense is wrong, since this product has been discontinued. But
+yes it did GC< but of course did not allow unsafe unchecked conversions
+etc.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Friday, November  1, 2002 at 10:31 AM
+
+> But any program you write with unchecked unions can be easily transcribed
+> to use unchecked conversion, the transformation is quite straightforward.
+
+True, but the AI itself does not define U_U in terms of U_C.
+If that's the semantics you want (which is fine with me),
+it seems like some wording is needed, similar to 13.9(11),
+which allows U_C of access values to cause erroneous execution.
+I don't see anything in the AI as written that would allow
+a copying garbage collector to ignore pointers hidden by unchecked
+unions.
+
+Actually, I think the analogy should not be with U_C, but with address
+clauses that make overlays.  The relevant permission for garbage
+collectors is 13.3(13).
+
+On the other hand, Robert is (sadly) correct when he says:
+
+> Mind you I think worrying about garbage collection is (to use the French
+> phrase) a "storm in a glass". I think the likelihood of anyone trying to
+> do garbage collection in a full blown Ada compiler is nil.
+
+which makes me think none of this matters in practise.  Sigh.
+
+> Furthermore, speaking as someone with a lot of experience in garbage
+> collected languages (from my SPITBOL and SETL days), I find the idea of
+> garbage collection in the presence of low level features that can mess
+> up memory to be pretty frightening. What can happen in such a situation
+> is that memory gets slightly messed up by the first GC, then the cancer
+> spreads until finally things totally collapse N GC's later, by which
+> time it is really hard to figure out what is going on :-)
+
+True.  However, I think this sort of decision should be left to
+programmers.  There's nothing to stop a project that uses a GC'ed
+implementation of Ada from having coding conventions that outlaw
+various low-level features.  Other than the fact that it will
+be hard to find such an Ada implementation!  :-(
+
+Also, an Ada implementation with GC ought to document how it deals with
+these cases, so programmers know what to avoid.
+
+----------------
+
+Since we're supposed to be doing editorial review, here are a couple of
+things I noticed:
+
+Typo at line 111:
+
+> Record representation clauses are permitted for unchecked unions. No space is
+> given for a discriminant; it is illgal to mention a discriminant explicitly in
+                                  ^^^^^^
+> a component clause.
+
+> An expression of an unchecked union type has "inferable discriminants"
+> if it is either a name of an object with inferable discriminants or a
+> qualified expression whose subtype_mark denotes a constrained subtype.
+
+It should allow parentheses: "if it is the name of an object with
+inferable discriminants, possibly parenthesized and/or qualified."
+(I believe there's another AI that uses this wording -- it's not worth
+expanding into the full-blown recursive definition.  I think "possibly
+parenthesized and/or qualified" makes it clear enough that
+(((T'((X))))) is OK.
+
+- Bob
+
+P.S. Let's put AI numbers in our Subject lines, OK?
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Friday, November 1, 2002 at 6:15 PM
+
+<<True, but the AI itself does not define U_U in terms of U_C.
+If that's the semantics you want (which is fine with me),
+it seems like some wording is needed, similar to 13.9(11),
+which allows U_C of access values to cause erroneous execution.
+I don't see anything in the AI as written that would allow
+a copying garbage collector to ignore pointers hidden by unchecked
+unions.>>
+
+Obviously such wording is required, since if you do overlay access
+values with say float's, there is an obvious path to what MUST
+in fact be erroneous, whether or not the AI bothers to say so :-)
+
+*************************************************************
+
+From: Robert I. Eachus
+Sent: Friday, November  1, 2002 at 12:48 PM
+
+>Actually, I think the analogy should not be with U_C, but with address
+>clauses that make overlays.  The relevant permission for garbage
+>collectors is 13.3(13).
+
+A voice of  reason!  I don't think the discussion should bee phrased in
+terms of what should or should not be legal.  This is editorial review!
+ But I do think an explicit sentence like 13.3.(13), is appropriate.
+ Let me put up a strawman:
+
+"For an Unchecked_Union, it is the programmer's responsibility to ensure
+that any read or write is the object references a valid value for the
+type of the value, otherwise program execution is erroneous."
+
+>On the other hand, Robert is (sadly) correct when he says:
+>
+>
+>>Mind you I think worrying about garbage collection is (to use the French
+>>phrase) a "storm in a glass". I think the likelihood of anyone trying to
+>>do garbage collection in a full blown Ada compiler is nil.
+>>
+>>
+>
+>which makes me think none of this matters in practice.  Sigh.
+
+No, it does matter in practice.  But not for full blown garbage
+collectors.  The real issue as I see it is when a storage managed type,
+either a magic type like Unbounded_String or a type with a managed
+storage pool, gets mixed with Unchecked_Unions.  We should allow it.  It
+is the programmer's responsibility to do it right. And there is no way
+the ARG can get into defining what doing it right means. (I would like
+to allow controlled components, under exactly the same rules, but that
+is not exactly an editorial comment. Hmmm...  Delete "A component
+declared in a variant_part of an unchecked union type shall not have a
+controlled, protected, or task part." from the legality rules, as the
+rule "  As the preceding rule: "All component subtypes of the type shall
+be C-compatible." seems sufficient. ;-)
+
+I can imagine writing a C function that returns a record or a reference
+to one of several predefined Unbounded_Strings.  The code could be
+portable between any Ada implementation that supports the needed pragma
+Interface and Unchecked_Union.  But I can't imagine any legality check
+we could define that could confirm that.  If the implementation wants to
+check that the returned value is a valid Unbounded_String before
+assigning it to another Unbounded_String, fine.  If it isn't checked and
+erroneous execution will result if the programmer gets it wrong?  Fine
+also.  But that is what this sentence would say, and also what the AI
+tries to say here:  "It is erroneous to perform any operation (in C or
+Ada) that would have failed a discriminant check had the discriminant
+been present at run-time."  But that sentence isn't in the proposed RM
+language.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Friday, November 1, 2002 at 6:28 PM
+
+Thankyou Robert for your suggestion:
+
+<<"For an Unchecked_Union, it is the programmer's responsibility to ensure
+that any read or write is the object references a valid value for the
+type of the value, otherwise program execution is erroneous.">>
+
+Right, that's exactly what was needed. And i it was omitted, it would
+still be implicitly there, because nothing else would make anyt sense
+at all :-)
+
+*************************************************************
+
+From: Tucker Taft
+Sent: Saturday, November 2, 2002 at 11:26 AM
+
+For what it's worth, there are at least two
+Ada implementations that support garbage
+collection, namely AppletMagic and JGNAT.
+
+Supporting unchecked union is pretty easy
+for AppletMagic, given the way we support
+variant records.  We leave space for
+all of the components, but we only use
+those that are associated with the "current"
+variant. This isn't as space-wasting as you
+would expect, because nested records and
+arrays are always separate objects, and we
+"null out" the nested object references
+as part of a whole-object assignment.
+
+In any case, omitting the discriminant wouldn't
+be any big deal.  Of course, the thing we
+can't do is support rep-clauses!
+
+I also see no great harm in adding an implementation
+permission, rather than a hard-and-fast rule, to
+require that access components in variant parts
+of an unchecked union have pragma Controlled
+applied to their type.   At least it shows we
+have thought about the problem.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November  2, 2002 at 11:44 AM
+
+<<For what it's worth, there are at least two
+Ada implementations that support garbage
+collection, namely AppletMagic and JGNAT.>>
+
+But they are nowhere near full language implementations wrt chapter
+12 and low level stuff.
+
+<<Supporting unchecked union is pretty easy
+for AppletMagic, given the way we support
+variant records.  We leave space for
+all of the components, but we only use
+those that are associated with the "current"
+variant. This isn't as space-wasting as you
+would expect, because nested records and
+arrays are always separate objects, and we
+"null out" the nested object references
+as part of a whole-object assignment.>>
+
+OK, but what's the point. The idea of unchecked union is to map into
+C unions. I find it useless (actually worse than useless - actively
+dangerous and undesirable) outside this narrow usage.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November  2, 2002 at 11:49 AM
+
+<<But they are nowhere near full language implementations wrt chapter
+12 and low level stuff.>>
+
+oops, I mean chapter 13.
+
+*************************************************************
+
+From: Robert I. Eachus
+Sent: Friday, November  1, 2002 at  1:50 PM
+
+There are two quasi-non editorial matters I'd like to bring up, and keep
+separate from the main thread.  I call these "quasi" because to me they
+look editorial, but could easily cause a discussion of non-editorial issues.
+
+First, what about 'Valid?  As I see it, no problem.  It applies to an
+object, which must have inferable discriminants, and it will check
+whether the object is a valid object of that subtype.  If everyone
+agrees, there should be another bullet added to Note 19 in 13.9.2, and
+probably a sentence in the Dynamic Semantics that indicates 'Valid
+checks the object for conformance to the inferable discriminants.
+
+Second, the paragraph on equality  really leaves me stunned:
+
+    Evaluation of the predefined equality operator for an unchecked union type
+    if either of the operands lacks inferable discriminants. [This includes the
+    case where the equality operator is invoked implicitly by the equality
+    operator for an enclosing composite type - if the unchecked union
+    component subtype is unconstrained, Program_Error is raised].
+
+Is this really necessary, or is it a contradiction? First  look at notes
+13 and 14 in 4.5.2.  Yes, I know these are notes, but we should  move
+very carefully when making changes that render notes incorrect.   Note
+13 says that predefined equality can only raise an exception  "...if the
+type has a tagged part whose primitive equals operator propagates an
+exception."  Oops!
+
+But the second note is much more telling.  "If a composite type has
+components that depend on discriminants, two values of this type have
+matching components if and only if their discriminants are equal.  Two
+nonnull arrays have matching components if and only if the length of
+each dimension is the same for both."
+
+Why is this a problem?  The equality paragraph is okay for the case
+where the values have non-inferable unchecked union subtypes.  But what
+about comparing two arrays with unchecked union components, or worse,
+discriminated record values whose values might contain unchecked union
+components.  We now have a required run-time check to decide whether to
+return false or raise Program_Error in cases where compilers currently
+may eliminate the equality test at compile time, or return false at
+run-time after comparing one or more discriminants.  Requiring complete
+evaluation like this may cause erroneous execution, which it seems to me
+is what the paragraph intends to prevent.
+
+The minimum fix it seems to me is to require Program_Error for
+subcomponents only in the case where they are "matching components" or
+subcomponents of matching components.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Friday, November 1, 2002 at 6:33 PM
+
+<<The minimum fix it seems to me is to require Program_Error for
+subcomponents only in the case where they are "matching components" or
+subcomponents of matching components.>>
+
+I would completely remove the requirement for raising Program_Error.
+This is supposed to be a low level feature for interfacing to C and
+which should not result in any generation of junk code.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at 11:29 AM
+
+> First, what about 'Valid?  As I see it, no problem.  It applies to an
+> object, which must have inferable discriminants, and it will check
+> whether the object is a valid object of that subtype.  If everyone
+> agrees, there should be another bullet added to Note 19 in 13.9.2, and
+> probably a sentence in the Dynamic Semantics that indicates 'Valid
+> checks the object for conformance to the inferable discriminants.
+
+'Valid is only allowed for scalars, so I don't think this is an issue.
+If I'm missing the point, please explain with an example.
+
+> Second, the paragraph on equality  really leaves me stunned:
+>
+>     Evaluation of the predefined equality operator for an unchecked union type
+>     if either of the operands lacks inferable discriminants. [This includes the
+>     case where the equality operator is invoked implicitly by the equality
+>     operator for an enclosing composite type - if the unchecked union
+>     component subtype is unconstrained, Program_Error is raised].
+>
+> Is this really necessary, or is it a contradiction?
+
+Yes, it is really necessary.  You can't do "=" without knowing what the
+discriminants are.
+
+Yes, it contradicts the NOTE in 4.5.2(33), as you note:
+
+>... First  look at notes
+> 13 and 14 in 4.5.2.
+
+(Note that it's para 33, not 13.)
+
+The easiest fix is to delete the NOTE.
+
+>...  Yes, I know these are notes, but we should  move
+> very carefully when making changes that render notes incorrect.   Note
+> 13 says that predefined equality can only raise an exception  "...if the
+> type has a tagged part whose primitive equals operator propagates an
+> exception."  Oops!
+>
+> But the second note is much more telling.  "If a composite type has
+> components that depend on discriminants, two values of this type have
+> matching components if and only if their discriminants are equal.  Two
+> nonnull arrays have matching components if and only if the length of
+> each dimension is the same for both."
+
+I agree that there is a problem here.  This is a subtle semantic point,
+so Pascal might want to rule this "non-editorial".
+
+The intent is that all of these Program_Errors can be detected at
+compile time, except in a shared-generic-bodies situation.
+The only reason these are run-time errors is to avoid generic
+contract problems.  In practice, in a non-shared implementation,
+you would get a warning at compile time (as well as a run-time error),
+so we can think of these as essentially being compile-time errors.
+
+But the proposed wording does not accomplish that.  For example:
+
+    type T(Discrim: Integer := 1) is ...
+    pragma Unchecked_Union(T);
+
+    subtype S is T(Discrim => 1);
+
+    type A is array(Positive range <>) of T;
+    type B is array(Positive range <>) of S;
+
+    A1: A := ...;
+    A2: A := ...;
+    B1: B := ...;
+    B2: B := ...;
+
+I believe that the intent is that "A1 = A2" should raise Program_Error
+(probably with a compile-time warning), and "B1 = B2" should not.
+
+However, as worded, if A1 and A2 happen to be zero-length arrays,
+"A1 = A2" returns True.  To fix the problem, change the AI to say:
+
+    Program_Error is raised....
+
+        - Evaluation of the predefined equality operator for an
+          unchecked union type if either of the operands
+          lacks inferable discriminants.
+
+        - Evaluation of the predefined equality operator for a
+          composite type if the subtype of some subcomponent
+          lacks inferable discriminants.
+
+          AARM Annotatation: Program_Error is raised even if the
+          subcomponent(s) don't actually exist at run time.
+          For example, "A1 = A2", where A1 and A2 are zero-length arrays
+          will raise Program_Error if the component subtype
+          lacks inferable discriminants.
+
+> Why is this a problem?  The equality paragraph is okay for the case
+> where the values have non-inferable unchecked union subtypes.  But what
+> about comparing two arrays with unchecked union components, or worse,
+> discriminated record values whose values might contain unchecked union
+> components.  We now have a required run-time check to decide whether to
+> return false or raise Program_Error in cases where compilers currently
+> may eliminate the equality test at compile time, or return false at
+> run-time after comparing one or more discriminants.  Requiring complete
+> evaluation like this may cause erroneous execution, which it seems to me
+> is what the paragraph intends to prevent.
+>
+> The minimum fix it seems to me is to require Program_Error for
+> subcomponents only in the case where they are "matching components" or
+> subcomponents of matching components.
+
+I don't think that's the best fix.  The compiler should be allowed to
+detect all of these cases entirely at compile time, and not generate any
+code for doing the "=" test (other than just inserting "raise P_E;" in
+the object code).
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at 11:37 AM
+
+Robert Dewar says:
+
+> I would completely remove the requirement for raising Program_Error.
+> This is supposed to be a low level feature for interfacing to C and
+> which should not result in any generation of junk code.
+
+I agree with the principle, which I would state as "Efficiency is more
+important than safety for low-level features."  However, that principle
+does not apply here.  As I said in my reply to Robert Eachus, the checks
+we're talking about are really compile-time checks, even though they are
+Program_Errors for generic contract reasons.
+
+In other words, a program that uses Unchecked_Unions properly will never
+attempt to do an "=" in the bad cases, so there is exactly zero overhead
+for these run-time checks.  There is certainly no point in worrying
+about the efficiency of incorrect code.
+
+Low-level features should not be made less safe than they need to be,
+unless there is a real run-time cost.  If somebody uses "=" in a bad
+way, they should get an error -- that has no effect on efficiency,
+because they will remove that code from their program.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November 2, 2002 at 11:47 AM
+
+Well what you want of course is a proper error message, or at least a
+warning. This business of raising PE for obvious compile time errors
+is a bit silly. I suppose one can argue that a warning is mandated
+by the Annex H requirements, but it's a bit round about.
+
+The generic contract model is a bit silly here. So we have a rule that
+says, yes, you can sign the contract on the car, and the contract says
+the car will run, but as soon as you drive it out of the showroom
+it will blow up :-)
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November 2, 2002 at 11:48 AM
+
+Perhaps we could add implementation advice (perhaqps in chapter 1) that
+says that whenever there is a static rule requiring program_error
+then a warning must be given at compile time. It is OK to talk about
+undefined rubbish like warning msgs in IA.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at 12:19 PM
+
+> Well what you want of course is a proper error message, or at least a
+> warning. This business of raising PE for obvious compile time errors
+> is a bit silly. I suppose one can argue that a warning is mandated
+> by the Annex H requirements, but it's a bit round about.
+>
+> The generic contract model is a bit silly here. So we have a rule that
+> says, yes, you can sign the contract on the car, and the contract says
+> the car will run, but as soon as you drive it out of the showroom
+> it will blow up :-)
+
+Yes, it's silly.  But we have precedent.  ;-)  For example, the fact
+that you can't return a task to outside it's master has exactly the
+same properties: you get a warning *and* a run-time error, unless the
+compiler does shared generics.
+
+> Perhaps we could add implementation advice (perhaqps in chapter 1) that
+> says that whenever there is a static rule requiring program_error
+> then a warning must be given at compile time. It is OK to talk about
+> undefined rubbish like warning msgs in IA.
+
+I would not *object* to that, but it seems unnecessary: compiler
+writers are smart enough to figure it out on their own.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November 2, 2002 at  6:19 PM
+
+<<I would not *object* to that, but it seems unnecessary: compiler
+writers are smart enough to figure it out on their own.>>
+
+I don't think so, it is certainly not the case that all implementations
+warn on unblocked return from functions, which seems a truly simple case
+(by the way, it is an idiotic feature of Ada that this is not statically
+illegal. Ada is really marvelous here, it insists syntactically on stupid
+returns that are not needed (e.g. in a function that raises an exception
+and does nothing else), and it does not insist on returns where they
+are obviously needed :-)
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Sunday, November 3, 2002 at 10:18 AM
+
+I basically agree, although I think "idiotic" and "obviously needed" are
+overstating it.  I have seen quite a few cases in my own code where I
+had to put in a bogus "raise Program_Error;", because although it was
+obvious to *me* that the code can't get there, it wasn't obvious to the
+compiler.  Furthermore, why don't compilers understand that "pragma
+Assert(False);" prevents a path from falling off the end of a function,
+just as much as "raise"?  In other words, the basic idea is good,
+but the details are not "obvious".
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at 12:10 PM
+
+Well, I can't understand the wording proposed by Robert Eachus.
+There must be a typo in there.  Can you clarify?
+
+I don't agree that making U_U potentially erroneous in the presence of
+GC is the only solution.  Mike Yoder proposed two other possible
+solutions that are also quite feasible.  So I'm afraid Robert's Rule (of
+inventing RM wording that doesn't exist whenever the existing wording is
+nonsensical) works here.  ;-)
+
+The more I think about it, the less I like Robert Dewar's analogy with
+Unchecked_Conversion.  Consider a U_C:
+
+    function Cast is new Unchecked_Conversion(Integer, Integer);
+
+    X: Integer := 0;
+
+    Put_Line(Integer'Image(Cast(X));
+
+Here, the unchecked conversion is to same type, so surely the
+representation of X is a correct rep for type Integer, so surely this
+very-simple U_C must work properly in all implementations.  It is *not*
+impl-def, nor is it erroneous.
+
+Agreed?
+
+Now consider the analogous thing with Unchecked_Unions:
+
+    type T(Discrim: Boolean) is
+        record
+            case Discrim is
+                when True => X: Integer;
+                when False => Y: Integer;
+        end record;
+
+    pragma Unchecked_Union(T);
+
+    Var: T := (Discrim => True, X => 0);
+    ...
+
+    Put_Line(Integer'Image(Var.Y)); -- Erroneous!
+
+The above Put_Line call is erroneous, according to the AI.
+It is not implementation-defined *whether* it's erroneous.
+It is simply erroneous.  In particular, it is not just like
+an Integer-to-Integer U_C.
+
+This is because the code violates a Discriminant_Check,
+and pragma U_U causes an implicit pragma Suppress of Discriminant_Check,
+and if you violate suppressed checks, you're erroneous.
+
+I must admit that the programmer will likely get away with the
+erroneousness, and simply print out the integer equivalent of the
+address.  Whether that's "evil" or not is between that programmer and
+his implementer -- it's not our business.
+
+Likewise, an analogy between U_U and overlays-with-address-clauses is
+also inapt.  Overlays can work non-erroneously (if you read your
+compiler-specific docs carefully).
+
+Now suppose we add GC into the picture.  Suppose we unchecked-convert
+from an access value to a same-sized integer, and print out the
+integer.  That will work fine, even in GC'ed implementations.
+(It's the other way around that causes trouble.)
+
+But the U_U case is unrelated to U_C (in either direction).
+In the U_U case, we have either an integer or an access value,
+but we can't tell which at run-time.  We don't have both at the
+same time; only one component actually "exists" at any given time.
+
+Therefore, I lean more and more toward Mike Yoder's idea: if you have
+moving GC, then you better suppress GC on the access types inside U_U's
+(presumably via pragma Controlled).  Or Tuck's suggestion of at least
+allowing the GC'ed implementation to require that.
+
+*************************************************************
+
+From: Michael F. Yoder
+Sent: Saturday, November 2, 2002 at  1:21 PM
+
+Robert A Duff wrote:
+
+>Therefore, I lean more and more toward Mike Yoder's idea: if you have
+>moving GC, then you better suppress GC on the access types inside U_U's
+>(presumably via pragma Controlled).  Or Tuck's suggestion of at least
+>allowing the GC'ed implementation to require that.
+
+It isn't only for moving GC: consider deciding whether to collect an
+object when the only remaining reference to it is a "maybe" pointer.
+
+I'm coming to think Tucker's idea is better. In a distributed
+environment, I'd expect GC policies to vary on a per-partition basis.[1]
+So, if the partition policy is no GC at all, that's like putting pragma
+Controlled on all access types; U_U users can go wild. If it's
+compacting GC preserving address order, it's best to get the bad news
+about the U_U type at compile time. If it's a "conservative" collector,
+U_U users can still go wild. And so forth.
+
+I'd expect a serious GC implementation to assume the existence of
+policies that operate somewhat like scheduling policies.
+
+I think Tucker's suggestion is to say access types with pragma
+Controlled are always allowed, and other access types may be forbidden
+in circumstances specified by the implementation. That seems just right.
+
+[1] If you know a reason this shouldn't be so, please speak up.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at  3:56 PM
+
+I agree with what Mike Yoder says above.
+
+I've read lots of papers about distributed GC, but it still seems like
+science fiction, to me.  I don't know what the implications are for
+Annex E's "remote access types".  But I agree that GC policies could
+vary across partitions.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Saturday, November 2, 2002 at 12:43 PM
+
+Here's more editorial review of AI-216.  (I'm not sure the last item is
+"editorial".)
+
+The !proposal says:
+
+> it is illgal to mention a discriminant explicitly in
+> a component clause.
+
+but I don't see that reflected in the !wording.
+
+> The first_subtype_local_name of a pragma Unchecked_Union shall denote
+> an unconstrained discriminated record subtype having a variant_part.
+
+Should say "discriminated record first subtype"?
+
+> An object of an unchecked union type is defined to have an unchecked union
+                                                     ^^^^
+                                                     be
+> object.
+
+> Any name which denotes a discriminant of an object of an
+           ^^^^^
+           that
+> Unchecked_Union type shall occur within the declarative region of the type.
+
+> An unchecked union subtype shall not be passed as a generic actual parameter
+> if the corresponding formal type has a known_discriminant_part or
+> is a formal derived type which is not an unchecked union type.
+                           ^^^^^
+                           that
+
+> A view of an unchecked union object [(including a type conversion or
+> function call)] has "inferable discriminants" if it has a
+> constrained nominal subtype, unless the object is a component of an
+> enclosing unchecked union object which is subject to a per-object constraint
+                                   ^^^^^
+                                   that
+> and the enclosing object lacks inferable discriminants.
+
+> Program_Error is raised in the following cases:
+...
+>     Conversion from a derived unchecked union type to an unconstrained
+>     non-unchecked-union type if the operand of the conversion lacks inferable
+>     discriminants.
+
+Why "derived"?
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Saturday, November 2, 2002 at  6:17 PM
+
+<<Here, the unchecked conversion is to same type, so surely the
+representation of X is a correct rep for type Integer, so surely this
+very-simple U_C must work properly in all implementations.  It is *not*
+impl-def, nor is it erroneous.>>
+
+It is most certainly impl-def in the general case (i.e. where paras 6-10
+do not apply) see para 11:
+
+11   Otherwise, the effect is implementation defined; in particular, the
+result can be abnormal (see 13.9.1).
+
+Note that this means that accessing the result can be erroneous. I am not
+making this up, it's what the RM says.
+
+<<The more I think about it, the less I like Robert Dewar's analogy with
+Unchecked_Conversion.  Consider a U_C:>>
+
+It is a fairly reasonable comparison given that
+
+a) anythying that can be done with U_C can be done with U_U
+b) anything that can be done with U_U can be done with U_C
+c) a significant use in practice for unions in C is to get the effect of
+   U_C (see for example the recent gcc thread on this issue), so it is not
+   at all surprising that the Ada equivalent is similar to U_C.
+
+I must say that I consider that this feature has lost its way. The original
+motivation behind introducing this unsafe feature is to model a corresponding
+unsafe feature in C, namely unions.
+
+But now the language experts get to work and work hard to make this as
+respectable as possible, and furthermore, pile it up with all kinds of
+irrelevant semantics that have nothing to do with the original purpose.
+
+*************************************************************
+
+From: Robert I. Eachus
+Sent: Sunday, November 3, 2002 at  8:12 PM
+
+Robert A Duff wrote:
+
+>>First, what about 'Valid?  As I see it, no problem.  It applies to an
+>>object, which must have inferable discriminants, and it will check
+>>whether the object is a valid object of that subtype.  If everyone
+>>agrees, there should be another bullet added to Note 19 in 13.9.2, and
+>>probably a sentence in the Dynamic Semantics that indicates 'Valid
+>>checks the object for conformance to the inferable discriminants.
+>>
+>'Valid is only allowed for scalars, so I don't think this is an issue.
+>If I'm missing the point, please explain with an example.
+
+Sorry the second sentence got twisted around when trying to say what I
+meant.  An object of an Unconstrained_Union subtype of course has
+(sub)components which are scalar, as are the discriminants.  Checking
+'Valid for such a component should (where necessary) check the inferable
+discriminants as well as the bit patterns, if any.
+
+let me give an example:
+
+  type U_U(Error: Boolean)  is record
+     case Error is
+         when True => EC: Error_Code;
+         when False => SA: System.Address;
+     end case;
+end record;
+
+Return_Value: U_U(False) := Some_C_Function;
+
+...
+
+if Return_Value.SA'Valid then....
+
+Now I may know that if Some_C_Function returns an Error_Code, that in
+this implementation it is not a valid System.Address.  In that case I
+should be able to use Return_Value.SA as an address without getting bus
+error.  As far as I can see, this should require no extra work on the
+part of implementors, but it is certainly a special case use of ' Valid.
+ (And yes I know that System.Address is not necessarily a scalar type,
+but we are definitely in implementation dependent code here.)
+
+*************************************************************
+
+From: Robert I. Eachus
+Sent: Sunday, November 3, 2002 at  8:21 PM
+
+Robert A Duff wrote:
+
+>Yes, it is really necessary.  You can't do "=" without knowing what the
+>discriminants are.
+
+If one value has inferable discriminants and the other does not, can
+they be equal?  The reason I ask really has to do with the empty array
+problem. If I compare two objects of a type with an array of
+unchecked_union components whose bounds depend on discriminants, and one
+array is empty, what happens?  I certainly don't want Program_Error!
+
+>(Note that it's para 33, not 13.)
+
+NOTE 13, and yes it is unofficially para 33. ;-)
+
+>The easiest fix is to delete the NOTE.
+
+And better is to fix it.
+
+>...
+>I don't think that's the best fix.  The compiler should be allowed to
+>detect all of these cases entirely at compile time, and not generate any
+>code for doing the "=" test (other than just inserting "raise P_E;" in
+>the object code).
+
+Let me explain my problem with your approach, and it definitely is a generic
+contract model problem.  If I have a list package with a declaration like:
+
+  generic
+    type Element is private;
+    Max_Size: in Integer;
+  package Bounded_Lists is
+    type List is limited private;
+    ...
+    function Is_Empty(L: List) return Boolean;
+    ...
+  end Lists;
+
+I don't want to have to deal with the case that a List containing no values
+MUST raise Program_Error in some cases.  This is a distributed cost.  Yes, I
+can implement the list in a way that doesn't run into the problem, but that is
+exactly the distributed cost.  Right now the rules of the language state that
+empty arrays compare equal.  You want to change that, I don't.  Note that the
+actual List type would have a discriminated component something like:
+
+    subtype Size is Integer range 0..Max_Size;
+    Element_Array is array(Size range <>) of Element;
+    type Content(Actual_Size: Size := 0) is
+      record
+        EA:Element_Array(1..Actual_Size);
+      end record;
+    type List is record
+        C: Content;
+      end record;
+
+Currently most compilers when generating code to compare two elements of type
+List will generate something like:  ...
+      if A.C.Actual_Size /= B.C.Actual_Size
+      then return False;
+      else
+        for I in A.C.EA'range loop
+          if A.C.EA(I) /= B.C.EA(I) then return False; end if;
+        end loop;
+        return True;
+      end if;
+
+It is perfectly legal now to eliminate some of the comparisons on Element.  But
+your rule requires checking to see that no subcomponent of any Element contains
+an Unchecked_Union without inferable discriminants. If two comparable elements
+both lack inferable discriminants, I am happy to leave it to the programmer to
+decide whether he is satisfied with that.  One, does and one does not?  I see
+no problem with that case for SUBcomponents.  It can only happen when there are
+higher level discriminants (whether inferred for some containing type or
+actually present) that do not compare equal, so always return false.
+
+I would prefer to leave the top level case as a bounded error, because I don't
+see any realistic chance that anyone would care.  (Some people might even want
+it to compare the bits, but I don't think we should try to guarentee that.)  It
+is the composition case that I worry about.  There are real cases where a
+careful compiler vendor would have to generate worse code for existing programs
+that do not use Unchecked_Unions.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Monday, November 4, 2002 at  8:08 PM
+
+> If one value has inferable discriminants and the other does not, can
+> they be equal?
+
+In that case, the AI says raise P_E.  If X has inferrable discriminants,
+and Y does not, you have to qualify Y:
+
+    if X = Constrained_Subtype'(Y) then...
+
+which will then *not* raise P_E, but return either True or False.
+
+That seems like the right choice.  You don't want to infer the
+discriminants of Y from those of X -- that would be more complicated,
+and more error-prone.  (Of course the whole feature is error prone, but
+at least here the programmer can explicitly say what he *thinks* the
+discriminants are -- presumably a function of some data stored
+"elsewhere".)
+
+>...  The reason I ask really has to do with the empty array
+> problem. If I compare two objects of a type with an array of
+> unchecked_union components whose bounds depend on discriminants, and one
+> array is empty, what happens?  I certainly don't want Program_Error!
+
+I think you certainly *do* want P_E.  Well, what you really want is a
+compile-time error, but because of shared generics, the best we can do
+is P_E (plus a compile-time warning).
+
+> Let me explain my problem with your approach, and it definitely is a
+> generic contract model problem.
+
+But I don't understand whether you're talking about shared-code
+generics.
+
+I don't care about the efficiency properties of shared-code generics.
+I do care that they are feasible to implement (although some folks have
+given up even on *that* principle).
+
+And in the non-shared-code implementation, the compiler can tell *at
+compile time* whether P_E is to be raised, so there is *zero* efficieny
+cost in the non-P_E case.
+
+The key point here is that we expect precise compile-time warnings for
+the error case.  In order for that to be possible, we have to define the
+semantics so that empty arrays raise P_E in the same cases as non-empty
+arrays, because the compiler cannot tell whether the array is empty.
+The compiler *can* tell whether there are any non-inferrable
+subcomponent subtypes anywhere in there.
+
+If I'm missing something, and there really is distributed overhead (in
+the non-shared-code implementation), please show a more complete
+example, because I can't think of any.  As far as I can tell, the
+compiler can always detect this "has subcomponent subtypes with
+non-inferrable discrims" property at compile time.
+
+*************************************************************
+
+From: Robert I. Eachus
+Sent: Monday, November 4, 2002 at  3:10 PM
+
+>And in the non-shared-code implementation, the compiler can tell *at
+>compile time* whether P_E is to be raised, so there is *zero* efficieny
+>cost in the non-P_E case.
+
+This is where we disagree.  Either you are saying that Program_Error
+should be raised if the compiler can't prove that there will be no
+Unchecked_Union components without inferable discriminants at compile
+time, or you are asking compilers to solve the halting problem.
+Records--even records without discriminants--can have components with
+discriminants.  It is easily possible to create abstract types that have
+such hidden discriminants, and where those discriminants CHANGE during
+the execution of a program.
+
+The example I gave should have been sufficient.  If you have a List of
+the type given, and the Element type is an Unchecked_Union, what
+happens?  You seem to say, no problem, always raise Program_Error at
+compile time.  But what if I compare two List objects with no Contents?
+Are you saying Program_Error should be raised in this case?  That is
+the case I am really trying to pin you down on.  I don't see how you can
+have inferable discriminants for a component that is not there.
+
+>The key point here is that we expect precise compile-time warnings for
+>the error case.  In order for that to be possible, we have to define the
+>semantics so that empty arrays raise P_E in the same cases as non-empty
+>arrays, because the compiler cannot tell whether the array is empty.
+>The compiler *can* tell whether there are any non-inferrable
+>subcomponent subtypes anywhere in there.
+>
+>If I'm missing something, and there really is distributed overhead (in
+>the non-shared-code implementation), please show a more complete
+>example, because I can't think of any.  As far as I can tell, the
+>compiler can always detect this "has subcomponent subtypes with
+>non-inferrable discrims" property at compile time.
+
+Ah, that is exactly what you are saying.  Now it comes down to a wording
+issue, and I think a pretty major wording issue.  When are the
+discriminant(s) of a missing component inferable?  You seem to think
+that only when they are statically inferable is derivable from the AI.
+I think that the AI makes it clear that a (sub)component must exist
+before you can even ask the question.  Saying that the program must
+raise Program_Error and then hoping the compiler can figure out how to
+do it at compile time is just not acceptable.  You either have to go the
+extra mile of  defining when a component (statically) inherits (ouch!)
+the non-inferable discriminant property from its children, or allow the
+compiler to give the correct answer at run-time instead of
+Program_Error.  I don't understand why you are so steamed-up about this.
+We are discussing a case where any sensible programmer will expect
+either a junk answer or the correct answer.  Let me give an example:
+
+type Test(X: Integer := 0)  is record
+   Okay: Boolean := False;
+   case X is
+    when Integer'First..-1 =>
+         Y: Integer := 6;
+    when 0..Integer'Last  =>
+          Z: U_U_Array(1..X);
+   end case;
+  end record;
+
+  A, B: Test;
+begin
+   A := (-1, True, 3);
+   B := (0, False);
+   if A = B then -- must raise Program_Error!
+
+To me this is a way too heavy distributed burden on implementations to
+even be considered.  I might find a bounded error of False or
+Program_Error acceptable,  but I really prefer bounded error only when
+both values have comparable components and at least one does not have
+inferable discrimanants.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Monday, November 4, 2002 at  3:17 PM
+
+I strongly agree with this
+
+And I have trouble believinhg the horrible complex mess that has been made
+out of what should be a simple feature with very limited goals and no
+decorations :-(
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Monday, November 4, 2002 at  4:18 PM
+
+I really can't answer your e-mail until you answer my question:
+
+I wrote:
+
+> >But I don't understand whether you're talking about shared-code
+> >generics.
+
+*************************************************************
+
+From: Robert I Eachus
+Sent: Monday, November 4, 2002 at  7:57 PM
+
+>>>But I don't understand whether you're talking about shared-code
+>>>generics.
+>>>
+
+The issue has NOTHING to do with generics, shared or otherwise.  It has
+to do with your belief that whether or not a value CONTAINS a component
+of an unchecked union type (with or without inferable discriminants) can
+be determined at compile time.  To boil my argument down to its essentials:
+
+     1)  A record type with or without discriminants, can contain
+another record that has discriminants (with defaults) that do not depend
+on the discriminants of the enclosing record.
+
+     2) Objects of such a record type can be assigned new component
+values, at run-time, with different discriminant values.
+
+     3) One of those new values might have a variant part that contains
+a component of an unchecked union type, with or without inferable
+discriminants, or maybe some of each.
+
+     4) Therefore it takes a run-time check to determine whether or not
+such a component is present.
+
+The only reason that this affects generics is that there are a lot of
+generic packages out there which contain code that this paragraph will
+require be made significantly worse.  But there are non-generic
+abstractions with the same property.
+
+Now what I had thought was the original intent was much less disruptive.
+If two objects of a record type have different discriminants, they are
+not equal.  End of story.  If, and only if, you have to compare two
+unchecked union components in the process of determining equality, and
+one or more needed descriminants cannot be inferred, raise
+Program_Error.  Otherwise return the correct result.
+
+Now I happen to think that is a bit of overkill, and I also think that
+the implementation freedom to do the equality checks in some order as
+long as discriminants are checked before components that depend on them
+would result in implementation differences, but that is all okay.  Not
+perfect, but definitely tolerable.
+
+But let me take this program destroying new equality feature to the
+highest heights.  No, I wouldn't want to do this, but as I see the AI,
+it can happen.  Say I have a large system with a tagged type.  I add a
+new derived type to the tagged type that contains an component with an
+unconstrained unchecked union type.  Does existing code morph to raise
+Program_Error?  I hope not!  The possibility of Program_Error should
+only exist if the equality operation for the new subtype is called.
+ Note that in general it will only be called if two values with the new
+tag are compared.  Legislating any other result is going to require work
+by compiler writers, and I guarantee that the resulting code won't be as
+efficient as what exists now.
+
+*************************************************************
+
+From: Robert A. Duff
+Sent: Tuesday, November 5, 2002 at  3:54 PM
+
+> >>>But I don't understand whether you're talking about shared-code
+> >>>generics.
+> >>>
+>
+> The issue has NOTHING to do with generics, shared or otherwise.
+
+OK, thank you.  So you're *not* talking about shared generics.  Good.
+
+I apparently have not explained myself very well, so let me try again.
+I will:
+
+    Part 1.  Define my proposal in greater detail.
+
+    Part 2.  Show that this proposal *is* implementable (without solving
+    the halting problem), and involves *zero* distributed overhead.
+
+    Part 3.  Argue that this proposal is simpler than the AI as written.
+
+    Part 4.  Argue that this proposal is safer than the AI as written.
+
+If you disagree, please explain which part you're disagreeing with!
+
+
+Part 1.
+
+Consider RM-3.2.1(5):
+
+    A given type shall not have a subcomponent whose type is the given
+    type itself.
+
+This is entirely a compile-time rule.  Even empty arrays are not allowed
+to contain themselves.  This is the meaning of "subcomponent" that I was
+talking about -- not the concept of subcomponents that might or might
+not exist at run time.
+
+I was hoping I could get away with a simple statement in the same style
+as the above rule, but if you insist on the full-blown recursive
+definition, here goes:
+
+The AI already defines the notion of "inferable discriminants".  The
+cases where equality won't work are a U_U type without inferable
+discriminants, or a composite type *containing* such a U_U type, visibly
+or invisibly.  The AI as written defines this dynamically; I propose to
+define it statically.  (If anyone can think of a better term than
+"missing internal discriminants", please suggest one.)
+
+    The following specific types are defined to be "missing
+    internal discriminants":
+
+        - A composite type, if some subcomponent is an U_U without
+          inferable discriminants.
+
+        - A derived type, if the parent type is one of these.
+
+        - A package-private type or private extension, if the full type
+          is one of these.
+
+        - A generic formal type, if the actual type is one of these.
+
+Then we can say that predefined "=" raises P_E if the subtype of either
+operand lacks inferable discriminants, or if the type of the operands
+is missing internal discriminants.
+
+Note that the above talks about specific types.  Class-wide equality is
+defined in terms of the specific type(s) already.
+
+Part 2.
+
+I hope it is now clear that the "missing internal discriminants"
+property can be detected at compile time.  (I'm ignoring shared
+generics.)
+Do you agree with that?
+
+Even if a component is inside a variant part, or inside an array that
+could be empty in some cases, it still causes the outer type to be
+missing internal discrims.  So my proposal is to raise P_E when
+comparing variant records, where one variant has the evil property, even
+if that variant does not exist at run time.  Similarly, my proposal is
+to raise P_E on "=" of arrays-of-evil-things, even if the array is zero
+length.
+
+Note also that the "has inferable discrims" property is compile-time
+known, since it depends only on the constrainedness of the component.
+It does not depend on the values of discriminants or anything like
+that.
+
+Because the relevant properties are known at compile time, the
+determination of whether to raise P_E for a particular "=" can happen at
+compile time.
+
+Therefore, the implementation is trivial:  Compute the above property.
+On each predefined "=", either generate the usual code (which Robert
+Eachus outlined earlier), or else generate code to do "raise P_E;".
+
+It should also be clear that there is *zero* distributed overhead.
+Each non-U_U type either is "missing internal discriminants" or not.
+If so, we raise P_E, so we don't care about efficiency.
+If not, the generated code is identical to what it would be if
+U_U had never been invented.
+
+Note that class-wide equality is typically implemented by dispatching to
+the specific-type equality.  The compiler can tell (at compile time of
+each specific type) whether to generate "raise P_E" or to generate the
+normal equality code.  There is still zero overhead for class-wide
+equality here, because we're dispatching anyway.
+
+Part 3.
+
+It seems to me that replacing the whole "=" operation with a "raise P_E"
+is simpler than replacing pieces of it.  If you don't agree with that,
+surely you will at least agree that it's at least as simple.
+
+Part 4.
+
+My claim is that this proposal is safer than the AI as written.
+
+This is because if you have a type that might cause P_E intermittently,
+you will get a compile-time warning, and the warning will be precise
+(you *will* get P_E, so you better fix your code).  Furthermore, you
+will get P_E every time you call "=" on that type, so you will be less
+likely to miss the problem.
+
+Note that the RM allows predef "=" to compare the subcomponents in any
+order.  Therefore, in the AI as written, some implementations might
+return False, where other implementations raise P_E, simply because the
+former compared some non-U_U component first, and found them unequal.
+That seems like an undesirable nonportability; my proposal makes the
+raising of P_E deterministic -- for some types it will, for others it
+won't.
+
+I admit that this claim does not apply to class-wide equality.
+Class-wide equality does:
+
+    Compare tags; if unequal, return False.
+
+    Dispatch to specific equality.
+
+This code could raise P_E intermittently, depending on the tag values
+each time we get here.
+
+SUMMARY: My proposal is implementable with zero overhead, and safer
+(except in the obscure case of an unconstrained unchecked union inside a
+class-wide type).
+
+Part 5.  An example:
+
+    type T(D: Boolean) is
+        record
+            case D is
+                when True =>
+                    X: Some_Unconstrained_Unchecked_Union;
+                when False =>
+                    Y: Integer;
+            end case;
+        end record;
+
+    procedure P(X, Y: T) is
+    begin
+        if X = Y then ...
+    end P;
+
+In the AI as written, the "X = Y" will raise P_E only if X.D and Y.D are
+both True.  In my proposal, the "X = Y" will raise P_E every time.
+
+It seems to me that the "X = Y" call is simply wrong -- you shouldn't be
+using predefined "=" on types where some components *might* not be able
+to do predefined "=".  It seems better to catch this every time through
+the code, and at compile time via a warning.  The correct way to write
+the above code is to avoid "=" altogether, or else write a user-defined
+"=" on T that (or on Some_Unconstrained_Unchecked_Union) that knows
+where to gin-up the discriminants of X from.
+
+Does anybody have a convincing example of how the above sort of thing
+would be useful in practice?  I.e., where you can sneakily call
+predefined "=", but write the code carefully so that X.D and Y.D are
+never both True at the same time?  If so, then I will withdraw my
+proposal, and I will live happily with the AI as written.
+
+(Obviously, I can *construct* such an example -- just add "if not X.D"
+to the above.  But the question is, is it useful in practice?)
+
+Part 6.  Comments on Robert Eachus' objections:
+
+> The issue has NOTHING to do with generics, shared or otherwise.  It has
+> to do with your belief that whether or not a value CONTAINS a component
+> of an unchecked union type (with or without inferable discriminants) can
+> be determined at compile time.
+
+It can (for specific types) as I showed above.  Of course, like all
+compile-time checks, it's conservative.
+
+>...  To boil my argument down to its essentials:
+>
+>      1)  A record type with or without discriminants, can contain
+> another record that has discriminants (with defaults) that do not depend
+> on the discriminants of the enclosing record.
+>
+>      2) Objects of such a record type can be assigned new component
+> values, at run-time, with different discriminant values.
+>
+>      3) One of those new values might have a variant part that contains
+> a component of an unchecked union type, with or without inferable
+> discriminants, or maybe some of each.
+
+My proposal is to raise P_E regardless of which variant actually exists
+at run time, if *any* of those variants have a trouble-making
+component.
+
+>      4) Therefore it takes a run-time check to determine whether or not
+> such a component is present.
+>
+> The only reason that this affects generics is that there are a lot of
+> generic packages out there which contain code that this paragraph will
+> require be made significantly worse.  But there are non-generic
+> abstractions with the same property.
+>
+> Now what I had thought was the original intent was much less disruptive.
+>  If two objects of a record type have different discriminants, they are
+> not equal.  End of story.  If, and only if, you have to compare two
+> unchecked union components in the process of determining equality, and
+> one or more needed descriminants cannot be inferred, raise
+> Program_Error.  Otherwise return the correct result.
+
+I agree that this is the proposal in the AI as written, and I agree that
+it has zero overhead.  But my proposal also has zero overhead.
+
+> Now I happen to think that is a bit of overkill, and I also think that
+> the implementation freedom to do the equality checks in some order as
+> long as discriminants are checked before components that depend on them
+> would result in implementation differences, but that is all okay.  Not
+> perfect, but definitely tolerable.
+>
+> But let me take this program destroying new equality feature to the
+> highest heights.  No, I wouldn't want to do this, but as I see the AI,
+> it can happen.  Say I have a large system with a tagged type.
+
+Ah.  I had missed the class-wide "=" issue; thanks for pointing it out.
+I believe I have taken it into account correctly in the latest version
+of my proposal, as written above.
+
+>...  I add a
+> new derived type to the tagged type that contains an component with an
+> unconstrained unchecked union type.  Does existing code morph to raise
+> Program_Error?  I hope not!
+
+I hope so!  At least if the existing code dispatches to that new type.
+
+In the AI as written, the existing code will raise P_E when passed the
+new Tag, *sometimes*.  In my proposal, the existing code will raise P_E
+every time it gets the bad Tag.  Both are, unfortunately, intermittent,
+but my proposal is less so.
+
+>...  The possibility of Program_Error should
+> only exist if the equality operation for the new subtype is called.
+
+Agreed.
+
+>  Note that in general it will only be called if two values with the new
+> tag are compared.  Legislating any other result is going to require work
+> by compiler writers, and I guarantee that the resulting code won't be as
+> efficient as what exists now.
+
+Yes, I agree with that.  I have modified my proposal above so that it
+works in this case, and is still zero overhead.
+
+From an earlier message:
+
+> type Test(X: Integer := 0)  is record
+>    Okay: Boolean := False;
+>    case X is
+>     when Integer'First..-1 =>
+>          Y: Integer := 6;
+>     when 0..Integer'Last  =>
+>           Z: U_U_Array(1..X);
+>    end case;
+>   end record;
+>
+>   A, B: Test;
+> begin
+>    A := (-1, True, 3);
+>    B := (0, False);
+
+You're missing "Z => ...".
+
+>    if A = B then -- must raise Program_Error!
+
+Yes, my proposal is to raise P_E here.
+
+> To me this is a way too heavy distributed burden on implementations to
+> even be considered.
+
+I can't imagine why this would cause *any* overhead.  We know at compile
+time that this will raise P_E, and we generate "raise P_E" code, and we
+don't care about efficiency.  In cases that don't raise P_E, we know
+*that* at compile time, and generate the same code we've always
+generated for "=".  If we're generating the same code we always did for
+non-U_U cases, then there is no distributed overhead; QED.
+
+>...I might find a bounded error of False or
+> Program_Error acceptable,  but I really prefer bounded error only when
+> both values have comparable components and at least one does not have
+> inferable discrimanants.
+
+I don't like bounded errors.  I don't see any need for them in this
+case.
+
+*************************************************************
+
+From: Robert I Eachus
+Sent: Tuesday, November 5, 2002 at  5:00 PM
+
+Ah, now Bob Duff and I are playing from the same sheet of music.  We
+may not agree on the right (musical) interpretation, but at least we now
+agree on what the (musical) notes say.
+
+I don't think this qualifies as editorial review at this point.  I think
+that the position that Bob Duff and I are taking on components of tagged
+types is a ramifiication of the current wording.  But I get the feeling
+that no one else had considered it.
+
+Second, I now understand that Bob Duff is arguing for a very
+conservative rule on raising Program_Error for equality.  My position is
+much more liberal.  Either requires wording changes. As long as the rule
+adopted doesn't cause contortions for implementors, I don't really think
+it matters. (The current AI wording does seem to require contortions.)
+Anyone who deliberately creates any of my examples is asking for
+trouble if they don't know the details of the actual implementation.
+This is not the normal and expected use of the pragma.  It was just my
+feeling that a literal reading of the AI could result in harmful tests
+being written with distributed costs.
+
+I don't think that there is such a thing here as a "right" resolution of
+these edge cases--other than, as I said above, don't cause implementors
+to go to a lot of effort.  I can't imagine anyone intentionally
+programming these sorts of structures except to test against the AI.
+The case will occasionally happen by error though, so we shouldn't
+completely ignore them.
+
+*************************************************************
+
+From: Robert Dewar
+Sent: Tuesday, November 5, 2002 at  5:23 PM
+
+<<I don't think that there is such a thing here as a "right" resolution of
+these edge cases--other than, as I said above, don't cause implementors
+to go to a lot of effort.  I can't imagine anyone intentionally
+programming these sorts of structures except to test against the AI.>>
+
+BUt once these difficulties have been pointed out, then even without
+a test, the damage is done, because to ignore these cases would
+be deliberately violating the stadnard and would mean that the
+DoC could not be signed.
+
+It is essential that all such difficulties be removed.
+
+I really see absolutely zero demand for this complexification of
+pragma Unchecked_Union. It seems a classic case of language designers
+running away with a feature to me and losing sight of its original purpose.
+
+*************************************************************
+
+From: Pascal Leroy
+Sent: Wednesday, November 6, 2002 at  4:20 AM
+
+I am withdrawing the following two AIs from the editorial review: no need to
+spend time on them, they won't go to the next WG9 meeting, and the ARG will
+discuss them again:
+
+AI 216: the recent discussion demonstrated that there are a number of
+significant problems with the AI as written; it goes back to the original
+author (Steve B., as I recall) for update.  I think we should follow Tuck's
+suggestion regarding interaction with garbage collection; Bob D.'s suggestion
+regarding equality; and Bob E.'s suggestion regarding validity and
+erroneousness.
+
+...
 
 *************************************************************
 

Questions? Ask the ACAA Technical Agent