Reputation: 464
Given the following type signatures, I'm able to compile and run the code under Maven with both JDK 6 and JDK 7, but Eclipse gives a "Bound mismatch: The type F is not a valid substitute for the bounded parameter <F extends Field<TP,F>>
of the type Field<TP,F>
" error in TupleVisitor.
I believe I need these types, although I understand this is difficult to motivate given the stripped-down example. Can anyone suggest a workaround that will let me continue to work in Eclipse?
public abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>>
public class VariableTuple<F extends Field<VariableTuple<F>, F>> extends Tuple<F, VariableTuple<F>>
public class ConstantTuple<F extends Field<ConstantTuple<F>, F>> extends Tuple<F, ConstantTuple<F>>
public class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>>
public class ConstantField extends Field<ConstantTuple<ConstantField>, ConstantField>
public class VariableField extends Field<VariableTuple<VariableField>, VariableField>
public interface TupleVisitor {
public <F extends Field<VariableTuple<F>, F>> void visit(VariableTuple<F> tuple, F field); //Eclipse error
public <F extends Field<ConstantTuple<F>, F>> void visit(ConstantTuple<F> tuple, F field); //Eclipse error
}
Filed bug at: https://bugs.eclipse.org/bugs/show_bug.cgi?id=422503
No simple workaround identified. While Rohit Jain's answer wouldn't work with a visitor pattern, I took his follow-up advice and removed F as a type parameter from Field.
Upvotes: 3
Views: 219
Reputation: 70584
The problem likely is that type parameters are provided by the caller. Given your declarations, somebody could declare
class ReallyConstantField extends ConstantField {}
and then invoke TupleVisitor.visit
while providing ReallyConstantField
for F
. The visit
method's type constraint would then read
ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>
so we use a ConstantTuple<ReallyConstantField>
. The type constraint for that class would then read
ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>
which is incorrect, as ReallyConstantField
is a ConstantField
which is a Field<ConstantTuple<ConstantField>, ConstantField>
, which is an inconvertible type.
That is, even though you declare a type parameter with an extends
bound, the only valid type argument is a single type. That is, you don't need a type parameter at all, but could simply declare:
void visit(ConstantTuple<ConstantField> tuple, ConstantField field);
Update
BTW, if these are supposed to be, as the example suggests, parallel class hierarchies with a one-to-one correspondence between the classes of different hierarchies, there is a simpler way to write the generics:
abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>> {}
class VariableTuple extends Tuple<VariableField, VariableTuple> {}
class ConstantTuple extends Tuple<ConstantField, ConstantTuple> {}
class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>> {}
class ConstantField extends Field<ConstantTuple, ConstantField> {}
class VariableField extends Field<VariableTuple, VariableField> {}
interface TupleVisitor {
public void visit(VariableTuple tuple, VariableField field);
public void visit(ConstantTuple tuple, ConstantField field);
}
Upvotes: 0
Reputation: 213411
This seems to a be a bug with eclipse, as it is compiling fine under javac for me too. In fact, there are few bugs related to self-referential Java generics related to eclipse that I found, but this isn't there. So, may be you should file one.
As for a workaround of this, I just found one, which I doubt you would like, as you have to make your interface generic. Yes, you heard it right. Declaring the type parameters with the interface itself, makes the code compile fine. Here's the compiling code:
interface TupleVisitor<E extends Field<VariableTuple<E>, E>,
F extends Field<ConstantTuple<F>, F>> {
void visit(VariableTuple<E> tuple, E field);
void visit(ConstantTuple<F> tuple, F field);
}
Of course there are two type variables, as the bounds on both of them are different. Check if this suits your need, because this really sounds to be as weird work-around, as the number of type parameters depends on the total number of implementors of Tuple
class (Actually weird, isn't it?). Or else you have to do some other changes.
Upvotes: 2