A DESCRIPTION OF THE REQUEST : I'd like to define a type hierarchy for which a child overrides a method in two parents with different return types. In general, this looks like: interface A {} interface B {} interface C extends A, B {} interface X { A foo(); } interface Y { B foo(); } interface Z extends X, Y { C foo(); } Per JLS 8.4.8.4 (or perhaps an equivalent section describing constraints on interface methods rather than class abstract methods), this is illegal because no interface can extend both X and Y: A is not substitutable for B, nor vice versa. However, it is impossible for any class that implements Z to violate type safety: foo() will always return an A, as required by X, and will always return a B, as required by Y. JUSTIFICATION : There are useful type hierarchies that can't be expressed without relaxing this restriction. For example: /** A set of pairs. */ interface Relation<T1, T2> { Relation<T2, T1> inverse(); } /** A many-to-one relation. */ interface FunctionalRelation<T1, T2> extends Relation<T1, T2> { InjectiveRelation<T2, T1> inverse(); } /** A one-to-many relation. */ interface InjectiveRelation<T1, T2> extends Relation<T1, T2> { FunctionalRelation<T2, T1> inverse(); } interface OneToOneRelation<T1, T2> extends FunctionalRelation<T1, T2>, InjectiveRelation<T1, T2> { OneToOneRelation<T2, T1> inverse(); } On the flip side, I'm not aware of technical restrictions that make this difficult to allow. It's just a matter of relaxing the overriding restriction. EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - The compiler accepts declarations like that for OneToOneRelation without error. ACTUAL - javac produces an error: types InjectiveRelation<T1,T2> and FunctionalRelation<T1,T2> are incompatible; both define inverse(), but with unrelated return types ---------- BEGIN SOURCE ---------- public class TestOverriding { interface Relation<T1, T2> { Relation<T2, T1> inverse(); } interface FunctionalRelation<T1, T2> extends Relation<T1, T2> { InjectiveRelation<T2, T1> inverse(); } interface InjectiveRelation<T1, T2> extends Relation<T1, T2> { FunctionalRelation<T2, T1> inverse(); } interface OneToOneRelation<T1, T2> extends FunctionalRelation<T1, T2>, InjectiveRelation<T1, T2> { OneToOneRelation<T2, T1> inverse(); } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : The return type of one of the conflicting interfaces must be modified so that it is a supertype of the other, resulting in less precise typing (and probably leading to subsequent downcasting). For example, InjectiveRelation could simply inherit Relation.inverse() with return type Relation<T2, T1>.
|