Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't diamond infer types on anonymous inner classes?

Tags:

In Java 7 and later, diamond can be used to infer types on normally like so without an issue:

List<String> list = new ArrayList<>(); 

However, it can't for anonymous inner classes like this:

List<String> st = new List<>() { //Doesn't compile      //Implementation here  } 

Why is this? Logically in this scenario, I can definitely infer the type as String. Is there a logical reason for this decision where the type cannot actually be inferred on anonymous inner classes, or was it omitted for other reasons?

like image 627
Michael Berry Avatar asked Dec 11 '12 13:12

Michael Berry


2 Answers

In the JSR-334:

Using diamond with anonymous inner classes is not supported since doing so in general would require extensions to the class file signature attribute to represent non-denotable types, a de facto JVM change.

What I guess is that as everybody knows, anonymous class leads to a generation of its own class file.

I imagine that generic type doesn't exist within these files and rather replaced by the effective (static) type (thus declared by the explicit type like <String> at declaration object time).

Indeed, file corresponding to an inner class is never shared across multiple different instantiations of it, so why bother with generics into it?! :).

It would be more hardly achievable (and surely useless) for compiler to force an extension (by adding a special attribute for generics) to theses kind of class files.

like image 73
Mik378 Avatar answered Oct 24 '22 08:10

Mik378


google yields, after skipping posts from stackoverflow, http://mail.openjdk.java.net/pipermail/coin-dev/2011-June/003283.html

I'm guessing it's like this, usually an anonymous class is a concrete subclass of the apparent type

    interface Foo<N extends Number>     {         void foo(N n);     }      Foo<Integer> foo = new Foo<Integer>(){ ... } 

is implemented by

    class AnonFoo_1 implements Foo<Integer>{ ... }      Foo<Integer> foo = new AnonFoo_1(); 

Suppose we allow diamond inference on anonymous classes, there can be complicated case like

    Foo<? extends Runnable> foo = new Foo<>(){ ... } 

The inference rules yield N=Number&Runnable; following the prev implementation trick, we need

    class AnonFoo_2 implements Foo<Number&Runnable>{ ... } 

That is currently not allowed; the type arg to super type Foo must be a "normal" type.


However, the rationale is not very strong. We can invent other implementation tricks to make it work

    class AnonFoo<N extends Number&Runnable> implements Foo<N>     {         @Override public void foo(N n)         {             n.intValue();             n.run();         }     }      Foo<? extends Runnable> foo = new AnonFoo<>(); 

the compiler ought to be able to do the same trick.

In any case, at least the compiler should allow the majority of use cases that do not involve "undenotable types", like Foo<Integer> foo = new Foo<>(){...} It's a pity that these common/simple cases are unnecessarily forbidden too.

like image 27
irreputable Avatar answered Oct 24 '22 07:10

irreputable