PROPOSAL: abstract enums
vapor1 at teleport.com
Mon Mar 30 01:35:09 PDT 2009
>From: "Joseph D. Darcy" <Joe.Darcy at Sun.COM>
>Sent: Mar 29, 2009 11:54 PM
>To: Derek Foster <vapor1 at teleport.com>
>Cc: coin-dev at openjdk.java.net
>Subject: Re: PROPOSAL: abstract enums
>This proposal is incomplete. There are many other possible impacts of
>this change, including serialization; see
> "So you want to change the Java Programming Language..."
>for an account of all the aspects of the system adding regular enums
Thanks for the pointer. Actually, I read that page before I submitted my proposal, and I even paraphrased some of its contents in my proposal. That page, for instance, was what prompted me to suggest that Class.isEnum() should return false for abstract enumeration supertypes, in an attempt to stay consistent with your decision with regards to how anonymous subclasses associated with enum constants are handled.
>Of the extensible and non-extensible version of enum pattern, the JSR
>201 expert group chose the non-extensible variant and many other
>decisions and details of the original enum design flow from that
>fundamental decision. Revisiting that decision now is impractical.
With respect, I think you have misread my proposal. Please read it again, with the following caveat in mind: My proposal is NOT about extensible enums. In fact, I specifically put language in my proposal to forbid the type of extensibility that you appear to be concerned about. My proposal is intending to make a relatively minor change to how enums work, as opposed to the major change that adding extensible enums would entail. In particular, my proposal endeavors to make as few as possible changes to how the enumeration leaf classes behave, which is where the vast majority of the problems with designing the enum proposal came from.
The term "abstract enum" is vague, and can mean several different things. I have often found, in online discussions about the subject, that the people discussing it think that they are talking about the same interpretation of those two words, but in fact one subgroup of the conversation is talking about one interpretation of the phrase, and another is talking about a different one. The discussions in the bug reports I submitted are prime examples of this. This has led to a great deal of miscommunication about this subject.
The most common meanings that people attribute to the phrase "abstract enum" are:
1) ("extensible enums") An abstract enum would allow the declaration of enum constants in a superclass, and then additional enum constants in a subclass. Superclass/subclass relationships would apply to the constants, and it would be possible to create additional enumerated values in a subclass of an enumerated type declared in a superclass. This would have a variety of useful consequences such as the ability to add new enum constants to an existing type by subclassing. However, this causes severe problems as well, such as the inability for a supertype to ever know the full set of its enumerated constants as defined by all possible subtypes (even those which might not be loaded at the time), as well as various serialization problems and so forth. It creates nasty problems with serialization and causes quite a number of other unpleasant side effects.
2) ("abstract enums" as per my proposal) An abstract enum would NOT allow the declaration of enum constants in a supertype. The supertype isn't really an "enum" at all, any more than Enum<T> is -- it's really just an abstract super"class", which is declared with the enum keyword only because Java syntax happens to create a somewhat artifical distinction between the terms "enum" and "class", and because this allows a little bit of syntactic sugar to happen so the user doesn't have to know about the generic type parameter. Regardless, these supertypes are really just classes which happen to extend Enum<T> and have subtypes which really ARE enums. Only these leaf enum types would be allowed to declare enum constants, in the exact same manner that they are currently able to, including serialization and so forth.
I am aware of the battles that have been fought over extensible enums, and also that while it is a nice-sounding idea, that it is incredibly difficult (maybe impossible) to implement correctly. My proposal was specifically designed not to retread this ground. I am proposing something different, which unfortunately has a name that strikes a similar chord in many people's minds. I am interested in IMPLEMENTATION code sharing among enum classes using inheritance. I am not interested in creating hierarchies of enumeration constants, the ability to add new enumeration constants at runtime, in altering enum serialization, or in other changes affecting the INTERFACE to enumerated constants, which was what the whole furor about extensible enums was about.
With the above said, in reviewing your comment regarding serialization, I did notice something in the serialization document that I had previously missed: that introducing or removing a new superclass into an enumerated type will alter the serialization of the leaf class enumeration constants (due to the ObjectStreamClass of the enum leaf class mentioning its supertype(s)). This is analogous to (and no worse than) what happens with ordinary classes, and I don't think it would be horrible to just let this happen ("if you add or remove supertypes, your enum serialization will change"). However, in this case it is probably not necessary or useful to break serialization at all, since unlike ordinary classes, enums have no state to serialize (just a name) so there is no reason to include the supertype hierarchy in the serialization either.
So thank you, since you did find a weakness in my proposal which I will address in a later version. This problem appears to be relatively easy to fix, however. (Just require that enum constants be serialized as if the immediate supertype of the leaf class that declares them was Enum, even if it isn't. Since all that's being serialized is the name of the enum constant in the leaf class, the addition/deletion of a supertype should not affect serialization, and with this change, would not).
I will also add a section noting that abstract enums can be entered as perfectly normal abstract classes in class files, with only a single marking bit needed to annotate it so that the compiler can distinguish it from an identically formed Java class for the purposes of forbidding cross-inheritance between enums and classes. I will also clarify the rules regarding what is considered a valid supertype of an abstract or non-abstract, enum (basically, must be abstract, must extend Enum<T>, etc.), with reference to class file formats instead of just to source code.
With these changes, are there other areas in which you feel my proposal is unclear? If so, please let me know what they are.
More information about the coin-dev