java - Why isn't a conversion to "GenericType<?>" allowed here? -
this code causes compile error javac (but, notably, not 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 javac this:
foo.java:9: error: inconvertible types bar<?> bar = (bar<?>) foo; ^ required: bar<?> found: foo<cap#1> cap#1 fresh type-variable: cap#1 extends iterable<? extends string> capture of ? extends iterable<? extends string>
changing cast (bar) foo
(i.e. using raw type) allows code compile, changing type of foo
foo<? extends iterable<?>>
.
edit: hilariously, simple change causes eclipse reject, javac accept:
void test(foo<iterable<string>> foo) { bar<?> bar = (bar<?>) foo; }
and, both eclipse , javac reject one:
void test(foo<iterable<? extends string>> foo) { bar<?> bar = (bar<?>) foo; }
if programmer wants explicitly cast type x
type y
, language allow it, assuming programmer knows better compiler.
but guys @ java want prevent impossible casts, e.g. (cat)dog
. have glorious detailed section dedicated subject - http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.5.1
but, there problems these rules? and, compilers conform these rules? ... these questions complex , not interesting.
what should care whether cast makes sense; if make sense, , compiler refuses accept it, no problem, work around it.
in question, there 2 places insert wildcards, in foo< >
, , in iterable< >
. in each place, wildcard can
0. none 1. bounded "? extends something" 2. unbounded "?"
so let's explore combinations, , here's 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 cast makes sense or not, explained later.
in case 10 , 11
, code should compile, javac rejects it. either rules have problems, or javac has bugs.
let's see example, why case 00
makes sense , should compile
void test00(foo<iterable<string>> foo) { bar<?> bar = (bar<?>) foo; } question is, there class/interface `x`, such bar<x> <: foo<iterable<string>> => foo<iterable<x>> <: foo<iterable<string>> => iterable<x> = iterable<string> => x = string answer yes, 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 iterable<string> != iterable<? extends string>
and case 11
foo<iterable<x>> <: foo<? extends iterable<? extends string>> => iterable<x> <: iterable<? extends string> => x <: string
it surprising case 01
should not compile, although feels sensible. root problem is, iterable
convariant, , ought use wildcard anywhere it's used. ideally should declare
class bar<t> implements foo<iterable<? extends t>>
but life hell if insert wildcards everywhere. better solution declaration site variance. not sure if java ever add feature before retire.
Comments
Post a Comment