enhanced enums - back from the dead?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Dec 6 19:23:05 UTC 2018


On 06/12/2018 16:53, forax at univ-mlv.fr wrote:
>
> ----- Mail original -----
>> De: "Maurizio Cimadamore" <maurizio.cimadamore at oracle.com>
>> À: "Remi Forax" <forax at univ-mlv.fr>
>> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>> Envoyé: Jeudi 6 Décembre 2018 09:54:09
>> Objet: Re: enhanced enums - back from the dead?
>> Hi Remi, some comments inline.
>>
>> On 05/12/2018 21:43, Remi Forax wrote:
>>> Hi Maurizio,
>>> i think you have overlook the fact that raw types and inference also doesn't
>>> play well together.
>> As I said, I've played with this quite a bit and came out convinced that
>> usability wise it's good. Note that in the proposed model, enum
>> constants will have full generic types - e.g. Foo<String>; it's only
>> when you go to the supertype that the type system will say Enum<Foo>.
>> But this will only be used by APIs accepting some Enum<T> - so we're
>> fine, and this actually guarantees same inference results as before
>> generification of a given enum.
> yes, i'm worried about Foo.values()
>
>    public enum Foo<T extends Comparable<T>> implements Comparable<Foo<T>> {
>      S<>(""), I<>(42);   // JEP 301 mentions the diamond syntax
>
>      private final T t;
>    
>      private Foo(T t) {
>        this.t = t;
>      }
>    
>      @Override
>      public int compareTo(Foo<T> o) {
>        return t.compareTo(o.t);
>      }
>    
>      public static void main(String[] args) {
>        Arrays.stream(Foo.values()).sorted().forEach(System.out::println);
>      }
>    }

Can't quite understand what you mean - the code above is flawed in 
different ways; first you can't implement Comparable<Foo<T>> - as Enum 
already does that and with Comparable<Foo> in this case (because of the 
new treatment).

Secondly, you can't override compareTo - which is final in enum.

So, the correct example is this:

import java.util.*;

enum Foo<T extends Comparable<T>> implements Comparable<Foo> {
     S<String>(""), I<Integer>(42);   // JEP 301 mentions the diamond syntax

     private final T t;

     private Foo(T t) {
       this.t = t;
     }

     public static void main(String[] args) {
Arrays.stream(Foo.values()).sorted().forEach(System.out::println);
     }
   }


Which compiles with no issues.

>
>>> accessibility:
>>> Widening the type is usually a big No because of the security implication. The
>>> fact that the same code code has no security bug with version n but a security
>>> hole with version n + 1 scares me.
>> What scenario do you have in mind regarding enum constant pseudo-inner classes?
> any scenario that is using a Lookup object
Still not getting what is the security implication; one thing is  to say 
that you can reflectively inspect a class where you could not before; 
another is that doing so represents a vulnerability. The proposed rule 
says that the enum constant class gets same visibility as parent. So you 
are really saying that some constant class contains _security sensitive_ 
details, and that users relied on an *unspecified* compiler behavior 
that protected them, as javac made the class package-private. That seems 
a pretty strange argument.
>
>>> source compatibility:
>>> It's may not be a big issue because the JDK source doesn't use 'var'. If a code
>>> uses 'var' the sharp type will propagate more, so the JDK is not perhaps the
>>> best code to test.
>>>
>>> friend or foe:
>>> the rules for raw types are brutal as you said, but it's by design, it offers
>>> maximum compatibility and doesn't allow to mix raw and generic type easily so
>>> my students detect the missing angle brackets easily (IntelliJ still doesn't
>>> warn about missing angle brackets by default :( )
>>>
>>>
>>> Now about your example, instead of being functional and wanted each Option to
>>> type their argument, you can use ugly side effects instead.
>>> So the idea is to use a temporary class instead of a Map to store the data
>>> associated with an option. So an Option is something that takes a chunk of the
>>> command line arguments and do a side effect on the field of an instance of that
>>> temporary class.
>> Sure, there might be other ways to get there; what I did, I did it to
>> test usage of generic enums in a real world code base.
> it seems to be "the use case" for generics enum.

I get that you do not like the feature :-)

Other use cases have been discussed here:

http://mail.openjdk.java.net/pipermail/amber-dev/2017-April/000173.html

rest assured, the JEP might bear my name, but we're not looking into 
this to make javac code better.

Maurizio

>
>> Maurizio
> Rémi
>
>>> public class LineParsing {
>>>     private final HashMap<String, Consumer<? super Iterator<String>>> actionMap =
>>>     new HashMap<>();
>>>     
>>>     public LineParsing with(String option, Consumer<? super Iterator<String>>
>>>     action) {
>>>       actionMap.put(option, action);
>>>       return this;
>>>     }
>>>     
>>>     public void parse(List<String> args) {
>>>       var it = args.iterator();
>>>       while(it.hasNext()) {
>>>         actionMap.get(it.next()).accept(it);
>>>       }
>>>     }
>>>     
>>>     public static void main(String[] args) {
>>>       var bean = new Object() {
>>>         Path input = Path.of("input.txt");
>>>         boolean all = false;
>>>       };
>>>       
>>>       new LineParsing()
>>>           .with("-input", it -> bean.input = Path.of(it.next()))
>>>           .with("-all", it -> bean.all = true)
>>>           .parse(List.of(args));
>>>     }
>>> }
>>>
>>> regards,
>>> Rémi
>>>
>>>
>>> ----- Mail original -----
>>>> De: "Maurizio Cimadamore" <maurizio.cimadamore at oracle.com>
>>>> À: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>>>> Envoyé: Mercredi 5 Décembre 2018 17:14:59
>>>> Objet: enhanced enums - back from the dead?
>>>> Hi,
>>>> as mentioned in [1], the work on enhanced enum stopped while ago as we
>>>> have found some interoperability issues between generic enums and
>>>> standard enum APIs such as EnumSet/EnumMap.
>>>>
>>>> Recently, we have discussed a possible approach that might get us out of
>>>> the woods, which is described in greater details here:
>>>>
>>>> http://cr.openjdk.java.net/~mcimadamore/amber/enhanced-enums.html
>>>>
>>>> We have done some internal testing to convince ourselves that, from an
>>>> operational perspective, where we end up is indeed good. Some external
>>>> validation might also be very helpful, which is why we're also in the
>>>> process of releasing the internal patch we have tested internally in the
>>>> 'enhanced-enums' amber branch (we'll need to polish it a little :-)).
>>>>
>>>> Assuming that, usability-wise, our story ticks all the boxes, I think it
>>>> might be worth discussing a few points:
>>>>
>>>> * Do we still like the features described in JEP 301, from an
>>>> expressiveness point of view?
>>>>
>>>> * Both features described in JEP 301 require some sort of massaging. On
>>>> the one hand sharper typing of enum constants has to take care of binary
>>>> compatibility of enum constant subclasses into account (for this reason
>>>> we redefine accessibility of said subclasses along with their binary
>>>> names). On the other hand, with the newly proposed approach, generic
>>>> enums also need some language aid (treatment of raw enum constants
>>>> supertypes). Do we feel that the steps needed in order to accommodate
>>>> these sharp edges are worth the increase in expressive power delivered
>>>> by JEP 301?
>>>>
>>>> * Our proposed treatment for generic enums raises an additional, more
>>>> philosophical, question: what are raw types *for* and how happy are we
>>>> in seeing more of them (in the form of raw enum types)?
>>>>
>>>> Cheers
>>>> Maurizio
>>>>
>>>> [1] -
>>>> http://mail.openjdk.java.net/pipermail/amber-spec-experts/2017-May/000041.html


More information about the amber-spec-experts mailing list