[enhanced enums] - end of the road?

Peter Levart peter.levart at gmail.com
Thu Jun 15 14:43:33 UTC 2017


Hi Maurizio,

On 06/15/2017 03:55 PM, Maurizio Cimadamore wrote:
> I get what you are saying. But I think this intermediate supertype 
> feels too magic. After all, you're after a sneaky way to extend from 
> an enum - which is not something you can do in the source code. If it 
> was possible, then you could just add the supertype yourself
>
> e.g.
>
> enum Option {
>
> D extends Generic<String>
>
> ...
> }
>
> where Generic would be defined as the translated code you wrote.
>
> But since Generic cannot be written, you need to put that in the 
> Option declaration, which seems untidy - in other words, if I look at 
> the class declaration for Generic, there's nothing which tells me that 
> it extends from Option, which is a big red herring IMHO (what if 
> Generic is in a different sourcefile?).

The constraint would be that Generic can only be in the same compilation 
unit - i.e. as a static member class of the enum which designates it as 
a super type of constants. But I see your point - it would not have an 
"extends Option" clause in its declaration (the enum declaration would 
designate it as a subclass of enum type from the other way around), so 
it would be easy to misinterpret it.

> Also, you open up issues where changing your enum declaration is 
> effectively changing the supertype of a (seemingly) unrelated class - 
> meaning that if you have code outside which relied on that Generic 
> class, you could break them w/o changing the definition of Generic.
>
> That's why I think adding custom superinterfaces would be slightly 
> tidier - as the information goes exactly in the place where you need it.
>
>
> Regarding your point about casting with the 'get' method - well, it 
> seems to me the cast would be internal to the API - so it's not 
> something the client would see (e.g. the caller of 'get' would be able 
> to pass the enum constant just fine).
>
> Maurizio

...yeah, but the implementation of get would have to cast, meaning that 
there's something inadequate with the representation. Generics were 
meant to reduce the need of explicit casts.

I think there is a solution though which does not even require sealed 
interfaces. Take your example with Generic<T> as plain interface:

enum Option {
    D implements Generic<String>("-d", ...) { ... }
    PROC implements Generic<ProcOption>("-proc", ...) { ... }

    ...

}


...and then use the following method signature:

public <Z, O extends Option & Generic<Z>> Z get(O option) { ... }


Regards, Peter


>
>
> On 15/06/17 14:07, Peter Levart wrote:
>>
>>
>> On 06/15/2017 02:44 PM, Peter Levart wrote:
>>>>
>>>> enum Option implements Consumer<String> {
>>>>    D implements Generic<String>("-d", ...) { ... }
>>>>    PROC implements Generic<ProcOption>("-proc", ...) { ... }
>>>>
>>>>    ...
>>>>
>>>> }
>>>>
>>>> Which is not too terrible (in fact has been put forward by John as 
>>>> a comment in the JEP [1]).
>>>>
>>>
>>> This is similar, but not the same. In above example, Generic<T> is 
>>> not a subtype of Option. It's just an interface implemented by 
>>> constant's subclasses. So you can not access Option members via an 
>>> instance of Generic<T>... Generic<T> therefore has to declare all 
>>> the interesting methods that can then be implemented by Option. You 
>>> also have to accompany this solution with "sealed" interfaces if you 
>>> don't want other implementations of Generic<T> besides the enum 
>>> constants...
>>
>> ...in addition, you can not access/modify elements of EnumMap<Option, 
>> ...> using keys of type Generic<T> for example - you would have to 
>> cast which is awkward given that your example use case:
>>
>> public Z get(Generic<Z> option) { ... }
>>
>> ...would probably do just that...
>>
>> Regards, Peter
>>
>



More information about the amber-spec-experts mailing list