Issue
I've got a class hierarchy of the following kind:
class Declarations {
interface Function<I, O> {
interface BinaryFunction<I> extends Function<I, Boolean> {}
}
static abstract class FunctionImpl<I, O> implements Function<I, O> {
static class BinaryFunctionImpl<I>
extends FunctionImpl<I, Boolean>
implements Function.BinaryFunction<I> {}
}
interface Optimizer<I, O, F extends Function<I, O>> {
interface BinaryOptimizer<I>
extends Optimizer<I, Boolean, Function.BinaryFunction<I>> {}
}
static abstract class AbstractOptimizer<I, O, F extends Function<I, O>>
implements Optimizer<I, O, F> {}
static abstract class OptimizerImpl<I, O, F extends FunctionImpl<I, O>>
extends AbstractOptimizer<I, O, F> {
static class BinaryOptimizerImpl<I>
extends OptimizerImpl<I, Boolean, FunctionImpl.BinaryFunctionImpl<I>>
implements BinaryOptimizer<I> {}
}
}
The compiler stumbles upon the declaration of BinaryOptimizerImpl<I>
and says:
'
Optimizer
' cannot be inherited with different type arguments: 'BinaryFunctionImpl<I>
' and 'BinaryFunction<I>
'
But I don't understand the issue, as BinaryFunctionImpl<I>
implements BinaryFunction<I>
and both are passed the same parameter. So these two types should be compatible from my understanding. If BinaryFunction<I>
was a class rather than an interface, I'd understand that constrained type parameters don't allow for instantiating them with subclasses unless declared with ? extends Type
. But for interfaces, this wouldn't make sense, as you can never instantiate an interface directly.
All of the shown types are already in active use within the surrounding codebase, except for OptimizerImpl
/BinaryOptimizerImpl
, which must provide the respective Optimizer
interface. Also note that the inheritance from AbstractOptimizer
in OptimizerImpl
cannot be resolved by integrating it into OptimizerImpl
, as it is also inherited from elsewhere (I know, the naming isn't ideal, sorry!).
How to make this compile with minimal impact on the existing class hierarchy, i.e. changing only the lowest-possible (most specific) type layer, to reduce the impact on the existing codebase? Is there a way to make this compile by only changing the declaration of BinaryOptimizerImpl
? (Leaving away the obvious non-solution of not making it implement BinaryOptimizer
)
I hope my question is comprehensible, I had to abstract a lot. I've done quite some research on the semantics of Generics in Java, but there's a large variety of mistakes to be made and I couldn't find any explanation for this one.
Solution
I believe F
in Optimizer
cannot be both BinaryFunctionImpl
and BinaryFunction
at the same time, it must resolve to a single type.
What about
interface BinaryOptimizer<I, G extends Function.BinaryFunction<I>>
extends Optimizer<I, Boolean, G> {}
static class BinaryOptimizerImpl<I>
extends OptimizerImpl<I, Boolean, FunctionImpl.BinaryFunctionImpl<I>>
implements BinaryOptimizer<I, FunctionImpl.BinaryFunctionImpl<I>> {}
Answered By - peterz
Answer Checked By - Willingham (JavaFixing Volunteer)