Version 1.3 of ais/ai-00261.txt

Unformatted version of ais/ai-00261.txt version 1.3
Other versions for file ais/ai-00261.txt

!standard 13.13.2 (31)          01-02-15 AI95-00261/01
!standard 13.13.2 (34)
!class amendment 01-02-13
!status work item 01-02-15
!status received 01-02-13
!priority Low
!difficulty Medium
!subject Extending enumeration types
!summary
!problem
The addition of child libraries facilitates programing by extension. The child, which evolves from the parent, can be either a supplement to or specialization of the parent. In any case the specification of the child should be limited to types and methods specific to the child.
In the case of enumerated types, this approach is violated. Theoretically, the author of the software has to know in advance all of the values of the enumerated type. The child libraries would then specialize this type by employing subtypes.
Moreover, you may not be able to modify the base package (it is a purchased library, it belongs to another department, etc.) In that case, all you can do is declare a new enumeration type with the additional literals and provide conversion functions. But that is error-prone; if additional literals are added to the original type during maintenance, the same change will need to be applied to the new type. But that has to be done explicitly, and it is quite likely to be forgotten. In addition, the conversion routines probably use 'Pos and 'Val, and these will break silently if additional literals are added to the original type.
!proposal
Add enumeration extension types.
Syntax:
enumeration_literal_list ::= (enumeration_literal_specification {, enumeration_literal_specification}) enumeration_type_definition ::= enumeration_literal_list | new parent_enumeration_subtype_mark with enumeration_literal_list
Semantics for enumeration extension types:
The enumeration literals for the type include those corresponding to the parent_subtype_mark and the new enumeration literals. These are all declared at the point of the declaration.
For each enumeration literal of the parent, there is a corresponding literal for the new type (with the corresponding position and ordering). The position number of the first enumeration literal in the extension part is one more than the position number of the last enumeration literal of the parent type.
The parent_enumeration_subtype_mark shall not denote a formal derived enumeration type.
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.
Stream attributes for enumeration extension type alway use the default implementation (they are not inherited).
Enumeration representation clauses for an enumeration extension type can either specify all of the codes (as currently), or made specify only the values of the new literals. In that case, the range of the aggregate must be include all new literals, and no inherited literals; the coding of inherited literals is the same as that of the parent type.
!discussion
!example
Claw contains a package similar to the following:
package Claw.Image_List is type Image_List_Type is tagged private; type Image_Kind_Type is (Bitmap, Icon, Cursor); procedure Load_Image ( Image_List : in out Image_List_Type; Image_Name : in String; Image_Kind : in Image_Kind_Type); ... end Claw.Image_List;
Let's say that you need to create an extended image list object type that can load GIFs and JPEGs as well as bitmaps and icons. You could modify Image_Kind to add these items, but then you would be modifying the base package. If you don't "own" the package in question (as is the case if you are just using Claw), then modifying the source to the package means that every update to Claw means going back in and recreating the modifications. Even if you do "own" the package in question, you have to be careful not to add compatibility issues when you change a spec. We try not to change the spec. of Claw packages without a good reason, because doing so can break user code. In this case, if we add enumeration literals to Image_Kind_Type, Image_Kind_Type'Last will change, and that might break someone's code.
If you had a way of extending Image_Kind_Type, the new package would be easy to create:
with Claw.Image_List; package Claw.Extended_Image_List is type Extended_Image_List_Type is new Claw.Image_List.Image_List_Type with private; type Extended_Image_Kind_Type is new Claw.Image_List.Image_List_Kind with (GIF, JPEG); procedure Load_Image ( Image_List : in out Extended_Image_List_Type; Image_Name : in String; Image_Kind : in Extended_Image_Kind_Type); ... end Claw.Extended_Image_List;
with Claw.Image_List; use Claw.Image_List; package body Claw.Extended_Image_List is procedure Load_Image ( Image_List : in out Extended_Image_List_Type; Image_Name : in String; Image_Kind : in Extended_Image_Kind_Type) is begin case Image_Kind is when GIF => Claw.Image_List.Load_Bitmap (Image_List_Type(Image_List), Convert_GIF_to_Bitmap(Image_Name)); when JPEG => Claw.Image_List.Load_Bitmap (Image_List_Type(Image_List), Convert_JPEG_to_Bitmap(Image_Name)); when others => -- Original kinds. (Would be nice to have a -- way to specify this: -- Extended_Image_Kind_Type'parent'range) Claw.Image_List.Load_Image (Image_List_Type(Image_List), Image_Name, Image_Kind_Type(Image_Kind)); end case; end Load_Image;
end Claw.Extended_Image_List;
(Note that the implementation assumes that these are convertible. I don't think they are useful without that.)
There of course are other ways of doing this, but they get messier when the enumeration is longer. Also consider the advantage for maintenance to this version.
Imagine that Microsoft invents a new kind of image, the Bytemap. We probably would end up adding Bytemap to the Image_Kind_Type enumeration in that case. When the new version of Claw is released, you will start using this new version. With an extensible enumeration type, your extension to support GIF and JPEGs would continue to work unmodified, and it would immediately support Bytemaps. Using one of the workarounds, you extension would either work but fail to support Bytemaps, or it would have to be modified before it would even work.
!ACATS test
!appendix

From: Robert C. Leif, Ph.D.
Sent: Sunday, February 11, 2001 11:13 AM
Topic: Extensible Enumerated Types
Reference: RM95-3.5.1 (pp. 37)
Keywords: Extensible, Enumerated, Types, Supertypes

1. Discussion:
	1.1 Introduction:
The addition of child libraries facilitates programing by extension. The
child, which evolves from the parent, can be either a supplement to or
specialization of the parent. In any case the specification of the child
should be limited to types and methods specific to the child.

In the case of enumerated types, this approach is violated. Theoretically,
the author of the software has to know in advance all of the values of the
enumerated type. The child libraries would then specialize this type by
employing subtypes.

Another argument goes back to minimizing coupling and maximizing cohesion.
For instance, the universe of name prefixes could easily exceed 100. For
instance, in the case of Great Britain, all of the titles of nobility have
to be added. The military and public officials would also have to be
included. A simple example for this is a registration form for SIGAda. Since
one of the best rules for data entry, is to minimize user entry of strings,
pull-down menus with a list of choices are a good solution for the entry of
enumerated types. However, the use of a menu with a list of 100 or more
selections is highly user-hostile. Therefore a subtype will have to be used
to populate the menu. Since it is extremely doubtful that a significant
number of clergy or members of the nobility attend SIGAda, the number of
items in the Name.Prefix menu can be reduced by neither including the
prefixes for the clergy nor the nobility. It would be simpler to have the
values for the clergy and nobility in separate child packages that can if
need be withed. The parent package will have to be modified each time a
prefix necessary for the child package has been discovered to have been
omitted. It should be noted, that it is quite easy to omit, one or two items
in an enumerated type. The flexibility of being able to add elements to an
enumerated type will result in a smaller number of items being included in
the original enumeration and simplify the creation of child packages.

2. Possible Approaches:
type Prefix_Type is (None, Mr, Ms, Miss, Mrs, Dr, Prof, Rev, Other);

(1)
supertype Army_Prefix_Type is (Prefix_Type, Private, Corporal, Sergeant,
Lieutenant, Captain, Major, Colonel, General);

(2)
type Army_Prefix_Type is new Prefix_Type with (Private, Corporal, Sergeant,
Lieutenant, Captain, Major, Colonel, General);

(3)
type Army_Prefix_Type is (Prefix_Type'range & ((Private, Corporal, Sergeant,
Lieutenant, Captain, Major, Colonel, General));

Example (1) is expressive; however it requires a new keyword supertype,
which is an antonym of subtype and thus provides symmetry.
Example (2) uses the "is new" construct, which is severely overloaded.
Example (3) uses the "&" operator and is analogous to string handling.

****************************************************************

From: Michael Yoder
Sent: Tuesday, February 13, 2001 2:31 PM

I think the case with the most potential difficulty would be

     type E is new Wide_Character with (Fee, Fie, Foe, ...);

which isn't insuperably hard IMO.  I am personally enumerationophilic and
would welcome such an extension, but I suspect the issue has been discussed
previously.  :-)  Speaking as a user, I would rate this feature as nice but
not necessary, though there's been more than one case I can recall where it
would have been welcome.  I am sure I have heard numerous users wish for
it, but can't judge how intense these desires were.

A concomitant extension which would be desirable (especially when extending
Wide_Character) is a way to write a representation clause which specifies
values for only the new literals.  Something like

     for E use Wide_Character'Representation & (Fee => 16#10000#, Fie =>
16#10001#, ...);

Mike Yoder

****************************************************************

From: Pascal Leroy
Sent: Tuesday, February 13, 2001 4:34 PM

Extensible enumeration types are certainly an interesting idea.  In fact at
some point during the 9X process they were part of the Mapping Document, and
got trimmed.  I think Tuck mentioned them again during the last ARG meeting.

But if you feel that this feature should be added to the language, I
encourage you to write a detailed proposal on how this would be integrated
with the rest of the language, and how it could be implemented.  Coming up
with syntax is very easy (I have no doubt that the "right" syntax is #2,
btw) but that's only about 1% of the work.  I think that the ARG would be
much more interested in looking at this idea if there were a real proposal
on the table, rather than a one-line example of the syntax.

If we had a real proposal, it would also be possible to evaluate the
implementation complexity and balance that with the potential benefits.

If you are interested in writing such a proposal, just send it to
Ada-Comment and it will be given due consideration.

****************************************************************

From: Robert C. Leif, Ph.D.
Sent: Tuesday, February 13, 2001 8:55 PM

I have taken the liberty of cross-posting my reply to Comp.Lang.Ada, which
is where the previous discussion occurred. You wrote, "I encourage you to
write a detailed proposal on how this would be integrated with the rest of
the language, and how it could be implemented."

I did not see a requirement that in order to propose an extension to Ada one
must be an expert in Ada compilers. In fact in some cases, it may be that
such expertise could even be detrimental. As I have repeatedly stated, there
are both technology driven and market driven aspects to product development.
In my own field of Analytical Cytology (Biomedical Engineering), I would
never limit customer or marketing suggestions to only those that the
individual who made the proposal actually knew how to do the implementation.
In fact one major reason for selecting one of the 3 proposed implementations
is: How easy would it be to teach in a first year computer science course? I
might note that my suggestion came from the problem of implementing a
software package.

****************************************************************

From: Pascal Leroy
Sent: Wednesday, February 14, 2001 1:36 AM
To: Robert C. Leif, Ph.D.
Cc: Ada-Comment List
Subject: Re: [Ada-Comment] Extensible Enumerated Types

> I did not see a requirement that in order to propose an extension to Ada
> one must be an expert in Ada compilers.

There is certainly no such requirement.  The point I was trying to make is
that, for the ARG to start discussing an amendment to the language, there
has to be a detailed proposal on the table.  I was assuming that you had the
necessary knowledge of Ada to come up with such a proposal.  If not, then
fine, we all have our field of expertise and I for one would be unable to
say anything useful about Analytical Cytology.

But the main point remains: you won't find many people in the ARG who have
enough time and interest to write-up detailed amendments proposals for other
people's good ideas.  So while your comment provides one useful data point,
it is unlikely to be given high priority, unless some expert becomes excited
enough about extensible enumerated types to spend time spelling out the
details.

****************************************************************

From: dewar@gnat.com
Sent: Wednesday, February 14, 2001 8:14 AM

Well there is a detailed proposal I think, namely the one in the mapping
document. I would suggest that the submitter look at this and see if
it meets the needs, and if so, propose that as the starting point.

****************************************************************

From: Robert C. Leif, Ph.D.
Sent: Wednesday, February 14, 2001 10:34 AM

I have looked at 3 documents: map-rat-Mar92, map-spec-Mar92, and ms-4.6. I
would greatly appreciate a specific reference.
Thank you.

****************************************************************

From: Pascal Leroy
Sent: Wednesday, February 14, 2001 9:09 AM

Mike commented:

> Speaking as a user, I would rate this feature as nice but
> not necessary, though there's been more than one case I can recall where
it
> would have been welcome.  I am sure I have heard numerous users wish for
> it, but can't judge how intense these desires were.

I have personally run into a few issues where this capability would have
been useful, but not many.  In a number of instances where my first thought
was, I need extensible enumeration types, it turned out that more careful
analysis of the problem revealed that a data structure more complex than an
enumeration type was needed anyway.

Interestingly enough, this is true of Bob Leif's example.  The same
individual can be a Dr, a Colonel and an Earl, and he would probably use one
title or another (or a combination) depending on the context.  An extensible
enumeration type would force that poor person to choose exactly one title,
which would be unfortunate.

Robert suggested:

> Well there is a detailed proposal I think, namely the one in the mapping
> document. I would suggest that the submitter look at this and see if
> it meets the needs, and if so, propose that as the starting point.

That crossed my mind, but as I recall this was killed quite early in the
game, so I'm not sure if the proposal was very detailed.  Moreover, when
Tuck et al. wrote the mapping document they only had to be compatible with
Ada 83.  Now we also need to be compatible with Ada 95, and that may add
other constraints.

****************************************************************

From: Tucker Taft
Sent: Wednesday, February 14, 2001 11:33 AM

The Ada 9X proposal was not particularly detailed.  There were two
parts.  One was the type extension part.  That is essentially identical
to the "type Ext_Enum is new Enum with (d,e,f);" suggestion,
and that still seems like the most natural.

The other part was polymorphism, where Enum'Class would require
two words, typically, one being the tag, and the other being
the value.  In retrospect, this capability doesn't seem worth
the trouble, and there would be lots of wording complexity associated
with tagged discrete types, relating to pass-by-reference,
ordering, etc.

Supporting enumeration extension seems easy enough (though the
rep-clause issue is interesting), but it is not clear the benefit
is high enough to justify even the modest effort.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 14, 2001 11:58 AM

I agree. I went and looked in a dusty carton in the far corner of the
basement of our office, and looked at all of the old mapping documents.

The proposal disappeared between Mapping 2.0 (May 1991) and Mapping 3.0
(June 1991). These versions probably were internal use only (my copy of
Mapping 2.0 was faxed me from AETECH), so I doubt Dr. Leif could find it
anywhere.

So, here is the complete proposal (so far as I can find) from Mapping 2.0:

3.5.1 Enumeration Types

An enumeration type may be extended as part of a type derivation by
specifying additional enumeration literals. The enumeration literals for the
type include those corresponding to the parent and the new enumeration
literals. For each enumeration literal of the parent, there is a
corresponding literal for the new type (with the corresponding position and
ordering). The position number of the first enumeration literal in the
extension part is one more than the position number of the last enumeration
literal of the parent type.

Examples:

    type Boolean_with_Unknown is new Boolean with (Unknown);
       -- Boolean_with_Unknown has three enumeration literals,
       -- False, True, and Unknown with position numbers 0, 1, and 2.

    type Rainbow is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);
    type Full_Color is new Rainbow with (Brown, Black, White);
	 -- Full_Color is an enumeration type with the literals:
       -- Red, Orange, Yellow, Green, Blue,
       -- Indigo, Violet, Brown, Black, White

---

That's it. At this point, the mapping still had T'Class for untagged types.
For an untagged type, T'Class has the same operations and implementation as
T, but it also
has implicit conversions to and from types in the class rooted at T. (This
would now be the "covers" rules.)

The section on enumeration representation clauses is empty: apparently, the
interactions of the enumeration extensions with rep. clauses either wasn't
considered, or wasn't considered to be a problem.

Similarly, no changes are indicated in the Operations of Discrete Types
section.

My guess here is that the mapping team didn't see a lot of problems or
interactions with this proposal, but I doubt that every corner of the
language was explored. For instance, I don't see any discussion of the
visibility of the enumeration literals. I.e.

    package Pack1 is
        type Rainbow is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);
    end Pack1;

    with Pack1;
    package Pack2 is
        type Full_Color is new Pack1.Rainbow with (Brown, Black, White);
    end Pack2;

    with Pack2; use Pack2;
    procedure Main is
        Color : Full_Color := Red; -- Is Red visible here?
    begin
        null;
    end Main;

Anyway, enjoy. :-)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 14, 2001 12:58 PM

Tuck said:

> The other part was polymorphism, where Enum'Class would require
> two words, typically, one being the tag, and the other being
> the value.  In retrospect, this capability doesn't seem worth
> the trouble, and there would be lots of wording complexity associated
> with tagged discrete types, relating to pass-by-reference,
> ordering, etc.

I don't see any evidence of this in Mapping 2.0. Perhaps it was in an older
version??

****************************************************************

From: Tucker Taft
Sent: Thursday, February 15, 2001 10:21 AM

Look in section 3.4.3, paragraphs 2 and 3.  This explains
the (logical) representation of a value of tagged type T'Class.
All such values are discriminated unions over the class
rooted at T, with the tag as the implicit discriminant.
Enumeration types could be tagged, as could any kind of type,
by including the word "tagged" in the ultimate ancestor type
declaration.  Any type derived from a tagged type was itself tagged.

So the polymorphism I was describing only applied if the ultimate
ancestor enumeration was marked "tagged."  So essentially I am
saying we should not bring back elementary tagged types, even if
we bring back elementary type extension.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 11:53 AM

Yikes! I never looked at the definition of tagged types. We really had
elementary tagged types at one point?

In any case, I don't think that is a feature that we would need to
resurrect.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 14, 2001 1:30 PM

Tuck said:

> Supporting enumeration extension seems easy enough (though the
> rep-clause issue is interesting), but it is not clear the benefit
> is high enough to justify even the modest effort.

It seems to me that the benefit is mostly political: one less thing that
requires modifying a base class when extending.

This seems like a good (and cheap) thing to add in a full revision, but it
doesn't seem to have the importance to spend time on at this stage of the
effort (where we are trying to standardize additional important features for
implementors to use now).

****************************************************************

From: Michael Yoder
Sent: Wednesday, February 14, 2001 1:52 PM

I think the polymorphism should be dumped; it makes the feature not worth
the effort.  IMO there are two reasonable paths to adding such a feature,
assuming some shorthand for extension rep specs is devised:

(1) Just make the new type a separate type, and have no new semantics
beyond that.  Conversion between the old and new types must use 'Pos and 'Val.

(2) As in (1), but allow type conversions between two enumeration types if
one's root type is the iterated parent of the other's.  This would disallow
conversion between E1 and E2 if both were extensions of E0, for
example.  Conversion to a wider type would always work, conversion to a
narrower one could propagate Constraint_Error.

Under (1) the "is new" syntax is just a shorthand for existing constructs,
except for the treatment of pseudo-literals like Nul, Del, etc. in
extensions of Character and Wide_Character.  Under (2) the declaration can
be treated as shorthand for describing how name resolution works, but
additional type conversions become legal.

I'd favor going with (1); (2) could be added later since it's an extension
that would make no legal programs illegal.  Also, going with (2) would
require deciding whether to make Wide_Character an extension of Character.  :-)

>Supporting enumeration extension seems easy enough (though the
>rep-clause issue is interesting), but it is not clear the benefit
>is high enough to justify even the modest effort.
I agree.

****************************************************************

From: Robert C. Leif, Ph.D.
Sent: Wednesday, February 14, 2001 3:37 PM

You wrote:
"This seems like a good (and cheap) thing to add in a full revision, but it
doesn't seem to have the importance to spend time on at this stage of the
effort (where we are trying to standardize additional important features for
implementors to use now)."

Although I sympathize with the problem of priorites, I do believe that
Extensible Enummerated Types should be added to the to do list.


Your second example was:
------------------------------------------
    package Pack1 is
        type Rainbow is (Red, Orange, Yellow, Green, Blue, Indigo, Violet);
    end Pack1;

    with Pack1;
    package Pack2 is
        type Full_Color is new Pack1.Rainbow with (Brown, Black, White);
    end Pack2;

    with Pack2; use Pack2;
    procedure Main is
        Color : Full_Color := Red; -- Is Red visible here?
    begin
        null;
    end Main;
---------------------------------------------------
To my untutored mind, Red is visible.

****************************************************************

From: dewar@gnat.com
Sent: Wednesday, February 14, 2001 4:55 PM

<<Although I sympathize with the problem of priorites, I do believe that
Extensible Enummerated Types should be added to the to do list.>>

There is really no "to do list" in this sense. As Pascal notes, the first
step is for someone to prepare a detailed proposal. So the next step is
to find someone who is enthusiastic and knowledgable enough to write up
a detailed proposal for consideration.

****************************************************************

From: Robert A Duff
Sent: Wednesday, February 14, 2001 7:49 PM

> To my untutored mind, Red is visible.

I agree.  That is, the inherited enum lits are implicitly declared at
the place of the derived enum type.

****************************************************************

From: Ehud Lamm
Sent: Wednesday, February 14, 2001 4:12 PM

>
> It seems to me that the benefit is mostly political: one less thing that
> requires modifying a base class when extending.
>
> This seems like a good (and cheap) thing to add in a full revision,

I don't see a great political advantage. I also don't seem to understand
what is the real issue this feature is supposed to solve. It complicates the
language (though not by much is you kill the polymorphism part), for no
substantial gain. That's funcionality vs. complexity again.

I also think that having tagged type as the only mechanism of extensibilty
is better for orthogonality reasons.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 14, 2001 5:11 PM

The problem is one of creating extensions from packages that are out of your
control.

Let's try an example. Claw contains a package similar to the following:

   package Claw.Image_List is
       type Image_List_Type is tagged private;
       type Image_Kind_Type is (Bitmap, Icon, Cursor);
       procedure Load_Image (
            Image_List : in out Image_List_Type;
            Image_Name : in String;
            Image_Kind : in Image_Kind_Type);
         ...
   end Claw.Image_List;

Let's say that you need to create an extended image list object type that
can load GIFs and JPEGs as well as bitmaps and icons. You could modify
Image_Kind to add these items, but then you would be modifying the base
package. If you don't "own" the package in question (as is the case if you
are just using Claw), then modifying the source to the package means that
every update to Claw means going back in and recreating the modifications.
Even if you do "own" the package in question, you have to be careful not to
add compatibility issues when you change a spec. We try not to change the
spec. of Claw packages without a good reason, because doing so can break
user code. In this case, if we add enumeration literals to Image_Kind_Type,
Image_Kind_Type'Last will change, and that might break someone's code.

If you had a way of extending Image_Kind_Type, the new package would be easy
to create:

   with Claw.Image_List;
   package Claw.Extended_Image_List is
       type Extended_Image_List_Type is new Claw.Image_List.Image_List_Type
            with private;
       type Extended_Image_Kind_Type is new Claw.Image_List.Image_List_Kind
            with (GIF, JPEG);
       procedure Load_Image (
            Image_List : in out Extended_Image_List_Type;
            Image_Name : in String;
            Image_Kind : in Extended_Image_Kind_Type);
         ...
   end Claw.Extended_Image_List;

   with Claw.Image_List; use Claw.Image_List;
   package body Claw.Extended_Image_List is
        procedure Load_Image (
            Image_List : in out Extended_Image_List_Type;
            Image_Name : in String;
            Image_Kind : in Extended_Image_Kind_Type) is
        begin
            case Image_Kind is
                when GIF =>
                     Claw.Image_List.Load_Bitmap (Image_List_Type(Image_List),
                          Convert_GIF_to_Bitmap(Image_Name));
                when JPEG =>
                     Claw.Image_List.Load_Bitmap (Image_List_Type(Image_List),
                          Convert_JPEG_to_Bitmap(Image_Name));
                when others => -- Original kinds. (Would be nice to have a
                               -- way to specify this:
                               -- Extended_Image_Kind_Type'parent'range)
                     Claw.Image_List.Load_Image (Image_List_Type(Image_List),
                          Image_Name, Image_Kind_Type(Image_Kind));
            end case;
        end Load_Image;

   end Claw.Extended_Image_List;

(Note that the implementation assumes that these are convertible. I don't
think they are useful without that.)

There of course are other ways of doing this, but they get messier when the
enumeration is longer. Also consider the advantage for maintenance to this
version.

Imagine that Microsoft invents a new kind of image, the Bytemap. We probably
would end up adding Bytemap to the Image_Kind_Type enumeration in that case.
When the new version of Claw is released, you will start using this new
version. With an extensible enumeration type, your extension to support GIF
and JPEGs would continue to work unmodified, and it would immediately
support Bytemaps. Using one of the workarounds, you extension would either
work but fail to support Bytemaps, or it would have to be modified before it
would even work.

This isn't the sort of showstopping problem that "with type" is intended to
solve (for instance), but it certainly would help. I suspect the reason that
we don't have more cry for such features is that most Ada programmers don't
program by extension in the classic O-O way, and thus don't run into these
problems. Better supporting that style is a political gain for Ada (even if
it isn't a real gain).

Java doesn't have enumerations at all (supposedly) because they couldn't
figure out an appropriate extension mechanism. Clearly, some people think
this is important enough to throw the baby out with the bathwater; the least
we can do is consider it.

> I also think that having tagged type as the only mechanism of extensibility
> is better for orthogonality reasons.

Conceptually, everything should be extensible. The reason for limiting it is
that Ada is a pragmatic language: we want to be able to do things without a
substantial runtime penalty. That seems to be the case here. My main concern
here is one of priorities, not whether this is a good idea (it clearly is).

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 14, 2001 5:22 PM

Mike said:

> (1) Just make the new type a separate type, and have no new semantics
> beyond that.  Conversion between the old and new types must
> use 'Pos and 'Val.

You have to support conversions. Ada always supports conversions between
derived types, and it would be weird to change that. Moreover, you have to
have conversions, as the handling of derived subprograms is defined in terms
of conversions. (Of course you have derived subprograms here!) Not to
mention that fact that the conversions are a large part of the benefit of
this feature.

The only way to avoid that would be to say that the new type is *not*
derived. But then you'd really want a different syntax (it ought not look
like a derived type if it isn't one), and *then* changing to be derived
later would not be harmless.

****************************************************************

From: Tucker Taft
Sent: Thursday, February 15, 2001 10:11 AM

Like Randy, I can't imagine adding this feature without dealing
with conversion.  Half-baked amendments are definitely worse than
no amendment, in my view.

Clearly the new enumeration type is a derived type,
and all untagged types with a common ancestor allow some sort of type
conversion.  I would recommend raising Constraint_Error
on a type conversion if the value is outside the base range of the
nearest common ancestor.  After this check, the normal subtype range check
would be performed.

And yes, I would make Wide_Character an extension of Character.
Using type conversion to convert between the two is extremely natural,
and the base-range checking rule suggested above also seems natural.

For a rep-clause, the simplest rule would be to require named notation
in the enum rep aggregate if only the new literals are to have
their internal codes specified.  When using named notation,
the bounds of the aggregate should probably be either the entire
base range of the new type, or Parent_Type'Last+1 .. New_Type'Last,
nothing half way in between.

****************************************************************

From: dewar@gnat.com
Sent: Thursday, February 15, 2001 11:23 AM
To: ada-comment@ada-auth.org
Subject: Re: [Ada-Comment] Extensible Enumerated Types

<<And yes, I would make Wide_Character an extension of Character.
Using type conversion to convert between the two is extremely natural,
and the base-range checking rule suggested above also seems natural.>>

is this upwards compatible in all situations (couldn't find a counter
example, but it had me a bit worried).

****************************************************************

From: Tucker Taft
Sent: Thursday, February 15, 2001 11:56 AM

I don't see how it could be incompatible, since type conversion
involves using a subtype_mark, and overloading isn't permitted
on subtype names.

But of course, I could be wrong.  Incompatibilities are tricky
beasts, as we found out in the Ada 9X process ;-).  A more systematic
analysis would be appropriate as part of writing up the amendment
AI.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 1:43 PM

Let me try. :-)

Let's declare a nested function Wide_Character:

package Something is
    function Wide_Character (C : Character) return Standard.Wide_Character
is ...

    WC : Standard.Wide_Character;
end Something;

package body Something is
begin
    WC := Wide_Character (C); -- OK if we have conversions?
end Something;

with Something; use Something;
procedure Main is
   WC : Wide_Character;
begin
   WC := Wide_Character (C); -- Illegal now?
end Main;

Humm...does the visibility or the overloading get applied first? If it's the
visibility, then it there is no problem here. And then I don't see how you
could have a problem.

****************************************************************

From: Michael Yoder
Sent: Thursday, February 15, 2001 11:51 AM

>Clearly the new enumeration type is a derived type,
>and all untagged types with a common ancestor allow some sort of type
>conversion.  I would recommend raising Constraint_Error
>on a type conversion if the value is outside the base range of the
>nearest common ancestor.  After this check, the normal subtype range check
>would be performed.

I agree about the semantics of type conversion here.


>And yes, I would make Wide_Character an extension of Character.
>Using type conversion to convert between the two is extremely natural,
>and the base-range checking rule suggested above also seems natural.

I agree here also.

>For a rep-clause, the simplest rule would be to require named notation
>in the enum rep aggregate if only the new literals are to have
>their internal codes specified.  When using named notation,
>the bounds of the aggregate should probably be either the entire
>base range of the new type, or Parent_Type'Last+1 .. New_Type'Last,
>nothing half way in between.
>
>-Tuck

Let me try to nail this down.  If I had

     type E0 is (Fee);
     type E1 is new E0 with (Fie, Foe);
     type E2 is new E1 with (Foo);

you would make the first two of these rep specs legal; how about the
last?  Do you mean any parent type above, or only the immediate parent?

     for E2 use (1, 2, 3, 4); -- legal
     for E2 use (Foo => 5); -- legal
     for E2 use (Fie => 2, Foe => 3, Foo => 5); -- legal?

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 1:36 PM

I think immediate parent would be enough, and it would avoid maintenance
problems (in that adding a literal to the middle type would not break the
rep. clause). But I don't care much.

****************************************************************

From: Christoph Grein
Sent: Thursday, February 15, 2001 12:18 AM

>    package Claw.Image_List is
>        type Image_List_Type is tagged private;
>        type Image_Kind_Type is (Bitmap, Icon, Cursor);
>        procedure Load_Image (
>             Image_List : in out Image_List_Type;
>             Image_Name : in String;
>             Image_Kind : in Image_Kind_Type);
>          ...
>    end Claw.Image_List;
>
>
>    with Claw.Image_List;
>    package Claw.Extended_Image_List is
>        type Extended_Image_List_Type is new Claw.Image_List.Image_List_Type
>             with private;
>        type Extended_Image_Kind_Type is new Claw.Image_List.Image_List_Kind
>             with (GIF, JPEG);
-- Would we also have here both inherited programs
         procedure Load_Image (
              Image_List : in out Extended_Image_List_Type;
              Image_Name : in String;
              Image_Kind : in Image_Kind_Type);
         procedure Load_Image (
              Image_List : in out Image_List_Type;
              Image_Name : in String;
              Image_Kind : in Extended_Image_Kind_Type);
-- or only the first one?
-- The first seems easy, it handles quite naturally (if not overridden)
-- only the when others part of the new operation below.
-- But what should the second one do if not overridden?


>        procedure Load_Image (
>             Image_List : in out Extended_Image_List_Type;
>             Image_Name : in String;
>             Image_Kind : in Extended_Image_Kind_Type);
>          ...
>    end Claw.Extended_Image_List;


****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 11:43 AM

Chistoph said:

> -- Would we also have here both inherited programs
>          procedure Load_Image (
>               Image_List : in out Extended_Image_List_Type;
>               Image_Name : in String;
>               Image_Kind : in Image_Kind_Type);
>          procedure Load_Image (
>               Image_List : in out Image_List_Type;
>               Image_Name : in String;
>               Image_Kind : in Extended_Image_Kind_Type);
> -- or only the first one?
> -- The first seems easy, it handles quite naturally (if not overridden)
> -- only the when others part of the new operation below.
> -- But what should the second one do if not overridden?

Humm, I hadn't thought about the second one.

But it isn't a problem; it's not primitive for Image_List_Type, and it will
work OK.

As with all derived types, the call is effectively:
     Load_Image (Image_List, Image_Name, Image_Kind_Type(Image_Kind);

Remember that conversions to the original enumeration type from an extended
one raise Constraint_Error if given a literal outside of the original type.
So
     Load_Image (IL, "My_Name", Extended_Enumeration_Type'(Bitmap));
would work fine, and
     Load_Inage (IL, "My_Name", GIF);
would raise Constraint_Error.

A more interesting problem with this example is that a call to Load_Image
would be ambiguous for the original enumeration literals (if there are use
clauses on both packages):

    Load_Image (IL, "My_Name", Bitmap); -- Ambiguous.

while

    Load_Image (IL, "My_Name", Claw.Extended_Image_List.Bitmap); -- OK

and

    Load_Image (IL, "My_Name", Extended_Image_Kind_Type'(Bitmap)); -- OK

Another reason to avoid promiscuous use clauses.

****************************************************************

From: dismukes@gnat.com
Sent: Thursday, February 15, 2001 2:28 PM

> package body Something is
> begin
>     WC := Wide_Character (C); -- OK if we have conversions?

The above is legal in any case because the function Wide_Character
hides the type name (independent of whether conversions are allowed).

> end Something;
>
> with Something; use Something;
> procedure Main is
>    WC : Wide_Character;
> begin
>    WC := Wide_Character (C); -- Illegal now?
> end Main;
>
> Humm...does the visibility or the overloading get applied first? If it's the
> visibility, then it there is no problem here. And then I don't see how you
> could have a problem.

Well, you can't do overload resolution until you know what's visible.
The type name hides the use-visible function, so the above has to
be a conversion to the type.  So no problem here.

****************************************************************

From: Robert A Duff
Sent: Thursday, February 15, 2001 6:31 PM

> > I don't see any evidence of this in Mapping 2.0. Perhaps it was in an older
> > version??
>
> Look in section 3.4.3, paragraphs 2 and 3.

Are these mappings available online somewhere?  (They should be, for
historical interest if nothing else.)  I have stacks of paper Ada 9X
documents in cardboard boxes in my attic, but I'm not sure how complete
they are, and anyway I'd prefer to search some on-line documents.

I joined the project in 1991, I think, but there was a lot of
interesting work before that.

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 6:45 PM

I doubt it. The Mapping 2.0 version was a draft version distributed only to
the DRs and the U/I teams. Thus, I doubt versions were made for posting at
Ada IC: especially since the conversion tools in those days were primitive.
There might be on-line versions of the public documents in the deep, dark
corners of the Ada IC web site, and that could be interesting, but there is
a lot of other work that probably is not on line at all.

I found the text I noted in a dusty box, after all, and laboriously keyed it
in by hand.

****************************************************************

From: Baird, Steve
Sent: Thursday, February 15, 2001 5:45 PM

The following is a list of some of the language issues that would
have to be addressed if enumeration type extensions were to be
added to the language (an action which I do not endorse).

No one of these would be particularly difficult to deal with,
but this is just a sampling and undoubtedly there would be others.

The point I am trying to make is that this would not be a "simple"
change.

  1) How would stream-oriented attributes behave, both in the case
     where the corresponding attribute of the parent type has the
     default implementation and in the case where it has a
     user-defined implementation?

  2) It seems like the parent subtype must be unconstrained.
     What would this mean
          type E1 is (Aa, Bb, Cc);
          subtype S is E1 range Aa .. Bb;
          type E2 is new S with (Dd, Ee);
     ?

  3) Perhaps it falls out, but clarification might be needed
     to ensure that a case like

         type E1 is (Aa, Bb, Cc);
         type Aa_Again is new E1 with (Dd, Aa);

     is rejected (i.e. the explicit-takes-precedence-over-implicit
     rule would not apply here).

     For similar reasons, enumeration extension of a formal derived
     (enumeration) type should be disallowed.

  4) 4.6(28) "...this can only happen on conversion to a modular
     type" would require modification. It might be worth stating
     explicitly that extension values of two structurally similar
     extensions are not corresponding values. For example,
         type E1 is (Aa, Bb, Cc);
         type E2 is new E1 with (Dd);
         type E3 is new E1 with (Dd);
         X3 : E3 := E3 (E2'(Dd));
     the elaboration of X3 would raise Constraint_Error.

  5) 3.4(9) and 13.1(5) would obviously require modification.
     Consider, for example, the attributes LAST and SIZE.

  6) This example should clearly be rejected,

         type E1 is (Aa, Bb, Cc);
         generic
             type E2 is new E1;
         package G is
             Static_Value : constant := E2'Pos (E2'Base'Last);
         end G;
         type E3 is new E1 with (Dd, Ee);
         package I is new G (E2 => E3);

     but on what basis? Does the definition of "static scalar
     subtype" need to be changed (i.e. treat a formal derived
     scalar type the same as a formal scalar type in 4.9(26)), or
     should the matching rules of 12.5.1(7-10) be tightened up?

  7) Would 3.4(19) require modification? Is it already clear
     (with no wording changes) that in this example
         package Pkg1 is
             type E1 is (Aa, Bb, Cc);
             procedure Proc (X : E1);
         end Pkg;
         package Pkg2 is
             type E2 is new Pkg1.E1 with (Dd, Ee);
         end;
     the subtype of Pkg2.Proc.X would have 3 values, not 5?

****************************************************************

From: Randy Brukardt
Sent: Thursday, February 15, 2001 7:49 PM

> The following is a list of some of the language issues that would
> have to be addressed if enumeration type extensions were to be
> added to the language (an action which I do not endorse).
>
> No one of these would be particularly difficult to deal with,
> but this is just a sampling and undoubtedly there would be others.
>
> The point I am trying to make is that this would not be a "simple"
> change.

Of course this is a simple change. If there are only 7 issues, it's real
simple. :-) From experience, there will be dozens of issues for any
proposal, no matter how simple, that was made to the ARG.

I don't find this proposal particularly important, but finding a few minor
issues to work out certainly shouldn't disqualify it from consideration.

In any event, I was directed to create an AI for this, and I will make it as
useful as possible. To that end, I'm creating a summary of the proposal in
the AI (no wording, though). *Then* the ARG can reject it.

>   1) How would stream-oriented attributes behave, both in the case
>      where the corresponding attribute of the parent type has the
>      default implementation and in the case where it has a
>      user-defined implementation?

There can't possibly be any question about the default behavior: it would be
the same as any other elementary type. Why would it be different? The
user-defined case is a bit more interesting. But there is no requirement
(with the Corrigendum wording) that an attribute is inherited in any way, so
I would suggest that it should simply always use the default implementation.
I'll add that to the AI.

>   2) It seems like the parent subtype must be unconstrained.
>      What would this mean
>           type E1 is (Aa, Bb, Cc);
>           subtype S is E1 range Aa .. Bb;
>           type E2 is new S with (Dd, Ee);
>      ?

No, there are no unconstrained enumeration subtypes. The point is that you
are deriving the *type*, not the *subtype*. The wording would need to be
clear on this. So, the effect is the same if you derive from S or from E1.

>   3) Perhaps it falls out, but clarification might be needed
>      to ensure that a case like
>
>          type E1 is (Aa, Bb, Cc);
>          type Aa_Again is new E1 with (Dd, Aa);
>
>      is rejected (i.e. the explicit-takes-precedence-over-implicit
>      rule would not apply here).

I think it falls out from the rule that the parent literals are redeclared.
But wording care would be necessary.

>      For similar reasons, enumeration extension of a formal derived
>      (enumeration) type should be disallowed.

Makes sense. I don't think an assume-the-best/assume-the-worst rule would be
justified here.

>   4) 4.6(28) "...this can only happen on conversion to a modular
>      type" would require modification. It might be worth stating
>      explicitly that extension values of two structurally similar
>      extensions are not corresponding values. For example,
>          type E1 is (Aa, Bb, Cc);
>          type E2 is new E1 with (Dd);
>          type E3 is new E1 with (Dd);
>          X3 : E3 := E3 (E2'(Dd));
>      the elaboration of X3 would raise Constraint_Error.

4.6(28): of course. That's obviously part of updating the wording for
conversions.

The tricky part of defining conversions is handling the case where there are
two
extensions with a common ancestor. The only rule that makes sense to me is
"For conversions between enumeration types with a common ancestor,
conversion is equivalent to converting to the ancestor, then to the target."
With that, there is no need to discuss "structurally similar extensions",
except perhaps in the AARM.

>   5) 3.4(9) and 13.1(5) would obviously require modification.
>      Consider, for example, the attributes LAST and SIZE.

3.4(9): of course. 13.1(5): I think you meant 13.1(15). I don't think there
is a problem with Size (which is subtype-specific): it only is inherited of
the subtype is statically matching, which it clearly is not. Last is neither
an operational nor representation attribute, so it doesn't fall under
13.1(15) anyway.

>   6) This example should clearly be rejected,
>
>          type E1 is (Aa, Bb, Cc);
>          generic
>              type E2 is new E1;
>          package G is
>              Static_Value : constant := E2'Pos (E2'Base'Last);
>          end G;
>          type E3 is new E1 with (Dd, Ee);
>          package I is new G (E2 => E3);
>
>      but on what basis? Does the definition of "static scalar
>      subtype" need to be changed (i.e. treat a formal derived
>      scalar type the same as a formal scalar type in 4.9(26)), or
>      should the matching rules of 12.5.1(7-10) be tightened up?

I don't get it. What's the problem here? I.Static_Value is clearly 5 in this
case.

Actually, 4.9(26) says that there aren't any static enumeration types, so it
needs to be fixed in any case.

That follows because there are no unconstrained enumeration subtypes. The
interesting part of the paragraph says:

A static scalar subtype is an unconstrained scalar subtype whose type is not
a descendant of a formal scalar type, or a constrained scalar subtype formed
by imposing a compatible static constraint on a static scalar subtype.

Since there are no unconstrained enumeration subtypes, the first part is
always false for an enumeration type. The second part requires already
having a static scalar subtype (which we don't have because the first part
is false). So there are no static enumeration subtypes. QED. :-)

>   7) Would 3.4(19) require modification? Is it already clear
>      (with no wording changes) that in this example
>          package Pkg1 is
>              type E1 is (Aa, Bb, Cc);
>              procedure Proc (X : E1);
>          end Pkg;
>          package Pkg2 is
>              type E2 is new Pkg1.E1 with (Dd, Ee);
>          end;
>      the subtype of Pkg2.Proc.X would have 3 values, not 5?

There are no unconstrained enumeration subtypes now. So enumeration
extension types would not change that, and certainly 3.4(19) would not need
to be changed. (The constraint would be inherited).


Thanks for improving the proposal (even if that wasn't your intent).

****************************************************************

From: Robert A Duff
Sent: Thursday, February 15, 2001 8:01 PM

> The point I am trying to make is that this would not be a "simple"
> change.

Thank you, Steve, for your careful analysis!
I agree that this would not be a "simple" change.

>   5) 3.4(9) and 13.1(5) would obviously require modification.
>      Consider, for example, the attributes LAST and SIZE.

I don't understand the issue with 13.1(5).  I see your point about all
the other stuff.  (You should print out Randy's fancy new version, which
has version 13.1(5/1), but I don't think it makes any difference in this
case.)

I have wanted extensible enumerated types several times, but it's not at
the top of my priority list.  Let's worry about "with private" first.
And extensible enumerated types later, or never.

****************************************************************

Questions? Ask the ACAA Technical Agent