Why isn't a conversion to "GenericType<?>" allowed here?
eclipse, generics, java
Solution
If a programmer wants to explicitly cast a type `X` to type `Y`, the language could just allow it, assuming that the programmer knows better than the compiler.
But the good guys at Java want to prevent some obviously impossible casts, e.g. `(Cat)dog`. So they have this glorious detailed section dedicated to the subject - http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
But, are there any problems with these rules? And, do compilers conform to these rules? ... These questions are too complex and not very interesting.
What we should care is whether the cast makes sense; if it does make sense, and the compiler refuses to accept it, no problem, just work around it.
In your question, there are two places to insert wildcards, in `Foo< >`, and in `Iterable< >`. In each place, the wildcard can be
0. None
1. Bounded "? extends Something"
2. Unbounded "?"
so let's explore all combinations, and here's my conclusion:
wildcard#1 wildcard#2 should_compile javac eclipse
00 - - Y Y N
01 - ? extends N N N
02 - ? N N N
10 ? extends - Y N Y
11 ? extends ? extends Y N Y
12 ? extends ? Y Y Y
20 ? - Y Y Y
`should_compile` means the cast makes sense or not, explained later.
In case `10 and 11`, code should compile, but javac rejects it. Either the rules have problems, or javac has bugs.
Let's see for example, why case `00` makes sense and should compile
void test00(Foo<Iterable<String>> foo) {
Bar<?> bar = (Bar<?>) foo;
}
the question is, could there be a class/interface `X`, such that
Bar<X> <: Foo<Iterable<String>>
=> Foo<Iterable<X>> <: Foo<Iterable<String>>
=> Iterable<X> = Iterable<String>
=> X = String
so the answer is yes, the cast makes sense.
and why case `01` should not compile
Foo<Iterable<X>> <: Foo<Iterable<? extends String>>
=> Iterable<X> = Iterable<? extends String>
=> NO SOLUTION
note that Iterable<String> != Iterable<? extends String>
and case `11`
Foo<Iterable<X>> <: Foo<? extends Iterable<? extends String>>
=> Iterable<X> <: Iterable<? extends String>
=> X <: String
It is surprising that case `01` should not compile, although it feels sensible. The root problem is, `Iterable` is convariant, and we ought to use a wildcard with it almost anywhere it's used. So ideally we should declare
class Bar<T> implements Foo<Iterable<? extends T>>
but life is hell if we insert wildcards everywhere. The better solution is declaration site variance. Not sure if Java will ever add that feature before we all retire.
Problem
This code causes a compile error with javac (but, notably, not with Eclipse 4.2.2!): ``` public interface Foo<T> { } class Bar<T> implements Foo<Iterable<T>> { } class Test { void test(Foo<? extends Iterable<? extends String>> foo) { Bar<?> bar = (Bar<?>) foo; } } ``` The error from javac is this: ``` Foo.java:9: error: inconvertible types Bar<?> bar = (Bar<?>) foo; ^ required: Bar<?> found: Foo<CAP#1> where CAP#1 is a fresh type-variable: CAP#1 extends Iterable<? extends String> from capture of ? extends Iterable<? extends String> ``` Changing the cast to `(Bar) foo` (i.e. using the raw type) allows the code to compile, as does changing the type of `foo` to simply `Foo<? extends Iterable<?>>`. EDIT: Hilariously, this simple change causes Eclipse to reject, but javac to accept: ``` void test(Foo<Iterable<String>> foo) { Bar<?> bar = (Bar<?>) foo; } ``` And, both Eclipse and javac reject this one: ``` void test(Foo<Iterable<? extends String>> foo) { Bar<?> bar = (Bar<?>) foo; } ```