Let's start with 3 interfaces. What they do is not important. Just note that Car is parameterized (), while Foo and Bar are not.
interface Foo {void testFoo();} interface Bar {void testBar();} interface Car<A> {A testCar();}
I want to βcomposeβ these interfaces, and this works fine if I explicitly create such composites:
interface FooBar extends Foo,Bar {} interface FooCar<A> extends Foo,Car<A> {}
However, I would prefer to implicitly combine interfaces through declarations of a limited type of various methods. For instance:
public <T extends Foo & Bar> T implicitFooBar() {return null;} public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;}
WORKS: The implictFooBar () method returns a type T that implements both the Foo and Bar interfaces (composite, if you like). The call to this method compiles, and I can avoid explicitly declaring the FooBar interface:
// implicit composition of Foo and Bar, GOOD FooBar implicitFooBar = implicitFooBar(); implicitFooBar.testFoo(); implicitFooBar.testBar();
FAILs: However, the implicitFooCar () call cannot be compiled. Error message: "The implicitFooCar () method in the GenericsTest type is not applicable for the arguments ()" (I wrapped my test code in the GenericsTest class.)
// implicit composition of Foo and Car<X>, FAIL! //Compiler says "The method implicitFooCar() in the type GenericsTest is not applicable for the arguments ()" FooCar<Number> implicitFooCar = implicitFooCar(); //compile error on method call implicitFooCar.testFoo(); Number n2 = implicitFooCar.testCar();
A compiler error indicates when a type declaration is compound and parameterized. For example, both of these compilations can be called just fine:
public <X> Car<X> justCar() {return null;} public <X, T extends Car<X>> T implicitCar() {return null;}
Question...
I suspect this is due to the erasure of styles, but I would like to understand the details of what is happening here. I read Oracle Generics tutorials, but I donβt see which combination of rules the implicitFooCar () method violates, while implicitFooBar () and implicitCar () are fine. I'm looking for an explanation of the academic style, not just a job.
Bonus
Interestingly, the next option to invoke the implicitFooCar () method works (without compiler errors). This indicates why the other version is not working, but I have not connected these points yet.
Test code (integer)
If you want to play with the code, here it is like one class.
public class GenericsTest { public static interface Foo {void testFoo();} public static interface Bar {void testBar();} public static interface Car<A> {A testCar();} public static interface FooBar extends Foo,Bar {} public static interface FooCar<A> extends Foo,Car<A> {} public <X> Car<X> justCar() {return null;} public FooBar explicitFooBar() {return null;} public <T extends Foo & Bar> T implicitFooBar() {return null;} public <X> FooCar<X> explicitFooCar() {return null;} public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;} public <X, T extends Car<X>> T implicitCar() {return null;} public void test() { justCar().testCar();
UPDATE
This is a compilation with javac version 1.8.0_60 (and _45 for comments), but the Eclipse (version 4.4.2.M20150204-1700) built into the ECJ compiler reports the error mentioned above. I have added an eclipse tag to this question as this may be an EJC problem.