简体   繁体   中英

Eclipse Generics Issue - Workaround?

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.

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.

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM