Search code examples
javagenericstypesinference

Simple java type inference fails


I have a generic interface ExternalState<T> and a class implementing it :

public class MockState<T extends Comparable<T>> implements ExternalState<T> {
}

Then, I have a class extending this implementation :

public class LunarOccultationState extends MockState<Boolean> {
    ...
}

and I have the following generic method :

  public  <T extends Comparable<T>> StateConstraintExpression.Builder equal(List<ExternalState<T>> states, T value) {
                for(var state : states){
                    StateConstraintEqual<T> sce = StateConstraintExpression.buildEqualConstraint(state, value);
                    this.constraints.add(new StateConstraintExpression(sce));
                }
            }
            return getThis();
  }

But when I try to call this method :

equal( lunarOccultationStates, false )

with lunarOccultationStates as List of LunarOccultationState, type inference fails. What is difficult to understand for me is that type inference in the following method (without a list) works :

  public  <T extends Comparable<T>> StateConstraintExpression.Builder equal(ExternalState<T> state, T value) {
                    StateConstraintEqual<T> sce = StateConstraintExpression.buildEqualConstraint(state, value);
                    this.constraints.add(new StateConstraintExpression(sce));
            return getThis();
        }

Could someone explain this?


Solution

  • You seem to think that List<LunarOccultationState> is a kind of List<ExternalState<T>>. It is not. See this post for why.

    What you can do is accept a List<? extends ExternalState<T>> instead. This type of list does not allow you to add things to it, which is the main reason why List<LunarOccultationState> is not a kind of List<ExternalState<T>>. But you are not adding anything to the list, so it's fine.

    public  <T extends Comparable<T>> StateConstraintExpression.Builder equal(List<? extends ExternalState<T>> states, T value) {
        for(var state : states){
            StateConstraintEqual<T> sce = StateConstraintExpression.buildEqualConstraint(state, value);
            this.constraints.add(new StateConstraintExpression(sce));
        }
        return getThis();
    }