CVS difference for ais/ai-00261.txt

Differences between 1.4 and version 1.5
Log of other versions for file ais/ai-00261.txt

--- ais/ai-00261.txt	2001/02/19 22:53:36	1.4
+++ ais/ai-00261.txt	2001/02/23 20:43:09	1.5
@@ -54,22 +54,23 @@
 literal of the parent type. Each literal in the extension part shall be
 distinct from any literal inherited from the parent type.
 
-[Open issue: range of the first subtype when the parent_subtype_mark does
-not denote the first subtype. Possibilities: Illegal (but watch the
-contract model violations); same as parent subtype; same as parent subtype
-except when Parent'Last = Parent'Base'Last (then extended).]
+If parent_enumeration_subtype_mark denotes a first subtype, then the first
+subtype of a enumeration extension type is constrained to the base range of
+the type. Otherwise, the first subtype has the same constraint as the
+parent_enumeration_subtype_mark.
 
 The parent_enumeration_subtype_mark shall not denote a formal derived
 enumeration type.
 
+The parent_enumeration_subtype_mark shall not denote a Boolean type (see
+3.5.3(1)).
+
 Type conversions between an enumeration extension type and its parent are
 allowed. For a conversion from the extension to the parent, a check is made
 that the value belong to the parent type. Constraint_Error is raised if this
 check fails. For conversions between enumeration types with a common ancestor,
 conversion is equivalent to converting to the ancestor, then to the target.
 
-All scalar formal types are non-static (modifying 4.9(26)).
-
 Stream attributes for enumeration extension type alway use the default
 implementation (they are not inherited).
 
@@ -86,24 +87,8 @@
 clause may require specifying a size for the extension if the extension does
 not fit in the size specified for the parent.
 
-[Open Issue: What about extended Boolean types? Do they get all of the Boolean
-treatment?
-Three solutions have been proposed:
-   1) No extensions from Boolean types. (similar to the rule for rep. clauses;
-      but some users may want to define three-valued logic). This
-      requires disallowing at enumeration extensions from formal types at
-      least in the body [assume-the-best with recheck in the spec].
-   2) Extensions from Boolean types are not Boolean types. Must fix contract
-      model problems.
-      2a) Define formal derived Boolean type is not a Boolean type (but might
-         be incompatible in very rare cases).
-      2b) A new kind of generic formal for enumeration extensions (which
-         is never a Boolean type.); extensions don't match normal
-         generic derived types. (heavyweight solution for minor problem).
-   3) Define meaning for all Boolean operations, including if. Probably like
-      non-binary modular types; for "if", anything other than False is treated
-      as True. (very heavyweight).
-]
+This proposal assumes that AI-263 (Scalar formal types are never static) has
+been adopted.
 
 !discussion
 
@@ -112,15 +97,47 @@
 as part of the conversion, there is no problem with such operations (they will
 raise Constraint_Error if any extension literals are used).
 
+We have a special rule for the constraint of an enumeration extension type,
+so that the first subtype is not constrained to the original subtype.
+But the constraint is preserved if the parent is not the first subtype, to
+work like other derived types.
+
+We considered alternative rules here: no special rule (so users generally
+would have to use 'Base on extensions -- but that seems silly); always ignoring
+the constraint of the parent_subtype_mark (but that seems inconsistent with the
+rest of the language); and extending the range only when Parent'Last is
+statically equal to Parent'Base'Last.
+
+The last idea seems appealing at first, but has weird effects. For instance,
+if the parent subtype is not a full range subtype, but happens to have the
+magic upper bound, it will be extended any way.
+
+Another issue is the difference in behavior between static and dynamic
+constraints. Consider:
+
+      type E is (Red, Blue, Green);
+      function Returns_Green return E is separate; --  always returns Green
+      subtype S1 is E range Red .. Returns_Green;
+      subtype S2 is E range Red .. Green;
+
+      type E1 is new S1 with (Mauve);
+      type E2 is new S2 with (Taupe);
+
+E1 (which has a dynamic subtype) would be constrained to Red .. Green, while
+the static parent E2 would be constrained to Red .. Taupe.
+
+For these reasons, and for simplicity, we adopt the first subtype rule.
+
 Extending from formal derived enumeration type must be disallowed, because
 we have to preserve the property that there are no duplicate literals
 (else 'Value would need redefinition); we want static literals; and possibly
 to avoid contract model problems with extending from Boolean types.
 
-Instead, we could define an assume-the-best rule to allow such types in the
-spec (with a recheck on instantiation).
+An alternative would be to define an assume-the-best rule to allow such types
+in the spec (with a recheck on instantiation). (In any case, they have to be
+prohibited in generic bodies.)
 
-4.9(26) needs to be modified to disallow the following example:
+AI-263 needs to be adopted to disallow the following example:
 
           type E1 is (Aa, Bb, Cc);
           generic
@@ -131,10 +148,36 @@
           type E3 is new E1 with (Dd, Ee);
           package I is new G (E2 => E3);
 
-This is most important if Static_Value is used in the body. Indeed, it probably
-is a mistake that such types are static in Ada 95.
+This is most important if Static_Value is used in the body.
 
+The question of extended Boolean types has been answered by prohibiting them.
+This is the easiest rule, and contract model violations are avoided by we're
+not allowing extensions from formal types. (Even if an assume-the-best rule
+is adopted, there is no problem here.)
+
+This rule does meam that a user is on their own if they want a three-valued
+logic; but that probably is as it ought to be. (Ada cannot anticipate all
+possible three-valued logics.)
+
+Alternatively, we could define the meaning of all of the Boolean operations
+(including conditionals and array operations) for an extension. This was judged
+to be far too complex.
+
+Another alternative would be to define that extensions of Boolean types are
+not Boolean types. This, however, has contract model problems if a generic
+has a formal derived type of type Boolean. (Then the operations available
+would depend on the actual, which is a no-no.) This could be fixed by
+says that a formal derived Boolean type is not a Boolean type (but that
+might be incompatible, although it seems very unlikely that any program is
+using a derived Boolean type) or by defining a new kind of generic formal
+for enumeration extensions, which is never a Boolean type (in this case,
+extensions would not match a normal derived type). That seems to be overkill,
+as formal derived enumeration types are not very useful; thus virtually all
+uses would be with extensions.
 
+Since the last alternative requires additional baggage, the rule prohibiting
+extensions from Boolean types was adopted.
+
 !example
 
 Claw contains a package similar to the following:
@@ -2238,6 +2281,152 @@
 end Announce_Error;
 
 ****************************************************************
+
+From: Ted Baker [baker@dad.cs.fsu.edu]
+Sent: Monday, February 19, 2001 4:57 PM
+
+| The POSIX Ada committee tried to make POSIX.Error_Code and POSIX.Signal_Code
+| enumerated types, but the requirement for independent extension kept raising
+| its ugly head and in the end, we settled for a distinctly non-Ada
+| "implementation defined integer type" with loads of defined constants.
+
+As an original member and later working group chair of the POSIX
+Ada bindings projects, I disagree with the conclusion above.  That
+is, we *thought* we wanted extensible enumeration types back when
+we did the original POSIX.5 binding, but now that we have gone
+through two revisions and extensions, and I have experience implementing
+and using the API, I don't believe it any more.
+
+Steve's suggested example looks very nice, but would not work in
+practice, because the POSIX error codes are *really* integers.  The
+OS implementation is always free to set additional error codes,
+that are not given names in the C-language API header files.  So,
+one were to use an Ada enumeration type to represent such values
+the binding would not know what to do with values that do not have
+names, when the OS sets them into errno.
+
+I am also uncomfortable about the fact that with an enumeration
+type in an API one begs programmers to use it fully, e.g., ranges,
+expressions using relational operators, and subranges in array
+declarations, aggregates, and case statements.  So long as
+extensions must be at the end of the range, these may seem fairly
+tame, but one must still be wary of code that uses of 'Last and
+'First breaking, since the specific meaning will change when the
+type is extended.
+
+****************************************************************
+
+From: dewar@gnat.com
+Sent: Monday, February 19, 2001 5:45 PM
+
+I definitely agree with Ted's conclusion here
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 19, 2001 7:49 PM
+
+Ted said:
+
+<<I am also uncomfortable about the fact that with an enumeration
+type in an API one begs programmers to use it fully, e.g., ranges,
+expressions using relational operators, and subranges in array
+declarations, aggregates, and case statements.  So long as
+extensions must be at the end of the range, these may seem fairly
+tame, but one must still be wary of code that uses of 'Last and
+'First breaking, since the specific meaning will change when the
+type is extended.>>
+
+Since an extension creates a new type, it certainly cannot be the case that
+existing code is broken by that type. Of course, someone could try to reuse
+existing code that wasn't "extension-safe", but that is always a problem
+with extensions of any kind. I don't see anything new or surprising or
+dangerous here.
+
+(Of course, the specific example appeared to be a case where using an
+enumeration type might have been a mistake. But that hardly could mean that
+*all* uses of enumeration types are a mistake!!)
+
+****************************************************************
+
+From: Deller, Steve
+Sent: Tuesday, February 20, 2001 2:29 PM
+
+Ted,
+Nice to hear from you :-).
+
+> I am also uncomfortable about the fact that with an enumeration
+> type in an API one begs programmers to use it fully, e.g., ranges,
+> expressions using relational operators, and subranges in array
+> declarations, aggregates, and case statements.  So long as
+> extensions must be at the end of the range, these may seem fairly
+> tame, but one must still be wary of code that uses of 'Last and
+> 'First breaking, since the specific meaning will change when the
+> type is extended.
+
+I do not understand this.  I thought 'First and 'Last allowed one to write a
+program that worked when type ranges were extended.  I would *expect* and
+*depend* on 'First and 'Last changing.  Also, I thought
+POSIX.Error_Enumeration'First and POSIX.Error_Enumeration'Last would *not*
+change just because someone defined a type extension, but would change only
+if code defining that type changed.
+
+What am I missing?
+
+> Steve's suggested example looks very nice, but would not work in
+> practice, because the POSIX error codes are *really* integers.  The
+> OS implementation is always free to set additional error codes,
+> that are not given names in the C-language API header files.  So,
+> were one to use an Ada enumeration type to represent such values
+> the binding would not know what to do with values that do not have
+> names, when the OS sets them into errno.
+
+While the C interface defines errors as integers, I disagree that they are
+*really* integers.  I believe they are enumerated errors, some of which we
+do not know the enumeration *yet*.  There is no arithmetic defined on these
+errors.  I have yet to see where one gets a "count" out of an error code.
+
+There are three categories of error codes:
+  1. POSIX required -- all POSIX systems support these
+  2. Known extensions -- we know what these error codes mean
+  3. Unknown extensions -- we have no idea what these error codes mean
+
+I, for one, would welcome an application that clearly distinguished these
+categories.  Or rather, an API that forced a straightforward application to
+distinguish "automatically" these three categories.  And I happen to think
+that extensible enumeration types would have provided the appropriate
+mechanism to write such an API.
+
+Yes, the value returned by the OS has to be numeric.  But POSIX could have
+provided an extensible enumeration type for all errors that are core errors,
+and provided a function for converting an OS value to any extension of that
+POSIX enumeration type.
+
+For the case where a returned numeric error code is not convertible to the
+(possibly extended) error code enumeration, the application pretty much has
+to bail.  After all, the meaning of the error is, by definition, unknown.
+
+I can think of several ways to handle unknown returned values in an API:
+exception, special value "UNKNOWN", boolean test for "known error".  I can
+also envision programs that could handle *any* extension of the POSIX
+enumeration so it worked "correctly" for all known errors.  And, when the
+meaning of "exceptional"/"unknown" error values became known, it would be a
+simple matter to extend the enumeration type appropriately.
+
+With POSIX.Error_Code as it is now, I do not know, when I see something of
+POSIX.Error_Code, whether the application code is trying to handle only core
+POSIX errors, Solaris POSIX errors, HPUX errors, and so on.
+
+With extensible enumeration types, I could see where code was POSIX-core
+only, and where it might be handling OS-specific extensions.  That
+information would be supremely helpful when porting an application from one
+OS to another.
+
+Anyway, I would have had fun arguing with you about the relative merits,
+since I always felt I came away with a better understanding of the issues.
+
+****************************************************************
+
 From: Randy Brukardt [Randy@RRSoftware.Com]
 Sent: Monday, February 19, 2001 2:41 PM
 To: 'Ada-Comment List'
@@ -2313,7 +2502,6 @@
 
 ****************************************************************
 
-
 From: Pascal Leroy
 Sent: Saturday, February 17, 2001 5:04 AM
 
@@ -2337,7 +2525,54 @@
 
 ****************************************************************
 
+From: Michael Yoder
+Sent: Monday, February 19, 2001 4:58 PM
+
+> Hmm.  My first thought was to say that My_Boolean is not a "boolean
+> type", so it's illegal to use it in if_stmts, and it doesn't get an
+> "xor" operator, and so forth.
+
+That's best if it doesn't break anything.
+
+****************************************************************
+
 From: dewar@gnat.com
+Sent: Monday, February 19, 2001 5:43 PM
+
+I think it is more reasonable to just make it illegal. Of what possible
+use is this extended boolean that is not a boolean?
+
+****************************************************************
+
+From: Randy Brukardt [Randy@RRSoftware.Com]
+Sent: Monday, February 19, 2001 7:34 PM
+
+It allows a different set of contract model violations. :-)
+
+That is, you have to prohibit some operations in generics if you adopt
+either of these rules. Exactly which ones are different for the two rules.
+
+One could use an extension of a Boolean to make a three-valued logic, where
+the user provided the appropriate operations. But I don't find that very
+compelling.
+
+****************************************************************
+
+From: Michael Yoder
+Sent: Monday, February 19, 2001 6:06 PM
+
+Forbidding extensions to Boolean would be tolerable to me, since if we
+forbid extensions of enumeration types in generic bodies the contract model
+problems with this go away.
+
+If extensions of Boolean were for multivalued logic, which is the only
+useful reason I can think of for making such extensions, you would probably
+want the new values to be *between* False and True.  That would be a bit
+much.  On the other hand, the user could redefine "<" etc. to achieve this.
+
+****************************************************************
+
+From: dewar@gnat.com
 Sent: Sunday, February 18, 2001 10:02 AM
 
 <<Boy, that's disgusting.  I am told there are programming languages out there
@@ -2375,6 +2610,52 @@
 
 ****************************************************************
 
+From: dewar@gnat.com
+Sent: Monday, February 19, 2001 4:57 PM
+
+I think it's a reasonable idea, it is exactly what GNAT does if you have
+a derived Boolean with a convention of C.
+
+I don't see that you can use Standard.Boolean, or are you saying you
+implement zero/non-zero semantics for all booleans (that sounds expensive!)
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 19, 2001 5:19 PM
+
+We use zero/non-zero semantics for Standard.Boolean when used in interfaced
+subprograms (not in the Ada code), so that any value other than 0 or 1 gets
+converted to 1 as part of the call (or return from call, for functions). And
+we use zero/non-zero semantics in all conditionals (which rarely costs
+extra).
+
+That won't work for uses of Boolean in convention C data types, created by C
+code, where the value is then used a normal logical operator (And Then and
+Or Else are really conditional control structures, so they work). So our
+implementation is not quite complete; as I said, no one has ever complained.
+(And you are correct that it would be too expensive to do that for standard
+Boolean for all operations.)
+
+****************************************************************
+
+From: dewar@gnat.com
+Sent: Monday, February 19, 2001 7:18 PM
+
+OK, I see, I think I prefer the GNAT approach which is to do this only
+for derived booleans with convention C (or Fortran), and then to do it
+uniformly.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, February 19, 2001 7:25 PM
+
+I agree. I wish I'd have thought of that at the time. (Too late now to
+change of course, lots of code depends on it.)
+
+****************************************************************
+
 From: Tucker Taft
 Sent: Saturday, February 17, 2001 1:23 PM
 
@@ -2592,6 +2873,33 @@
 
 ****************************************************************
 
+From: Michael Yoder
+Sent: Wednesday, February 21, 2001 12:55 PM
+
+
+The more I think about it, the more I dislike a rule that checks for
+matching of 'Last.  It would be like the rule that permits tweaking the
+bounds of fixed point types, usually when they are powers of 2--a clever
+idea that happens to work poorly in practice.  I'd prefer either of these
+two (I'm open to other possibilities of course):
+
+(1) A constraint is always inherited, so you must say "is new T'Base" to
+avoid getting a constraint imposed that excludes the new values.  Some
+(most?) will find this counterintuitive.
+
+(2) A constraint is inherited unless the parent subtype denotes a first
+named subtype.  You can, of course, use T'Base in any case, and then there
+is no constraint to inherit.  It is possible that some (most?) will find
+this even more counterintuitive, but I think it would cause fewer errors
+overall.
+
+My personal preference would, truthfully, be a third one: to undo the
+decision that makes first named subtypes of enumeration types be
+constrained.  However that's a preference expressed before exploring the
+ramifications of such a decision.  :-)
+
+****************************************************************
+
 From: Baird, Steve
 Sent: Sunday, February 18, 2001 6:18 PM
 
@@ -2724,5 +3032,31 @@
 (If you do, then we probably do need an AI on this, as it would imply a bug
 in the language.)
 
+[Editor's note: This thread continues in AI-00263.]
+
 ****************************************************************
+
+From: Michael Yoder
+Sent: Friday, February 23, 2001 11:26 AM
+
+The "check 'Last" rule seems to lead to an unpleasant consequence.  Consider:
+
+      type E is (Red, Blue, Green);
+      function Returns_Red   return E is separate; --  always returns Red
+      function Returns_Green return E is separate; --  always returns Green
+      subtype S1 is E range Returns_Red .. Returns_Green;
+      subtype S2 is E range Red .. Green;
+
+      type E1 is new S1 with (Mauve);
+      type E2 is new S2 with (Taupe);
+
+The rule must, presumably, demand that the constraint be static *and* that
+'Last match.  So E2 would include a new value and E1 wouldn't, even though
+their bounds were identical at run time.  Of course, this sort of behavior
+would occur for the "first named subtype" rule, but it seems less
+disturbing because the rule is frank about making a special case.
+
+****************************************************************
+
+
 

Questions? Ask the ACAA Technical Agent