views:

64

answers:

2

[UPDATE] The real situation was a bit more complicated than my initial question made it seem. I've changed the code a bit to reflect that.[/UPDATE]

I'm a bit stumped by the following behavior. Given code like:

interface Inter<T> {
  T makeT();
  void useT(T t);
}

public class Foo {
  public void bar(Qux q) {
    Inter<?> x = getInterForQux(q);
    x.useT(x.makeT());
  }

  Inter<?> getInterForQux(Qux q) {
    if( someTest(q) ) {
      return (Inter<Integer>) mkAnInterInt();
    } else {
      return (Inter<Double>) mkAnInterDouble();
    }
  }
}

Javac gives me the error:

useT(capture#478 of ?) in Inter<capture#478 of ?> cannot be applied to (java.lang.Object)

Whereas Eclipse gives me:

The method useT(capture#1-of ?) in the type Inter<capture#1-of ?> is not applicable for the arguments (capture#2-of ?)

Obviously, no matter what T is the result type of makeT() is the same as the parameter type of useT(). Why can't I do this? Is there a workaround?

+3  A: 

When you use wildcard, compiler can't see that the return type of x.makeT() and the parameter type of x.useT() are the same. In order to guarantee that they are the same, you should use generic method here:

public class Foo { 
    public <T> void bar(Inter<T> x) { 
        x.useT(x.makeT()); 
    } 
} 
axtavt
The actual case is not so trivial, as noted above. For one thing, `bar` is actually an interface method, so I can't just stick a type quantifier on it. But I think you can always refactor the code to make room for the quantifier by pushing the "scope" of T into a private method.
Chris Conway
+1  A: 

This is logical, since Inter<?>.makeT() can return anything, and Inter<?>.useT(..) consumes anything, but the two anythings can be different.

That would fix it:

public <T> void bar(Inter<T> x) {
    x.useT(x.makeT());
}
Bozho
It's not logical at all: `x` can only have one type and one type variable. But your suggestion is correct.
Chris Conway
it is - the generic types are erased at runtime.
Bozho
Yes, and obviously the compiler can't make use of anything that's not available at runtime.
Chris Conway
indeed - you might search for "type erasure"
Bozho