tags:

views:

110

answers:

3

When I have a Java generic function like:

<T> T choose(T a, T b) { }

and I call it from somewhere, how can I find out what type is inferred for T?

Edit: Type inference happens at compile time. So what I'm asking is, how do I get the compiler to tell me some information (the inferred type) it has during compilation, but that doesn't make it into the .class file?

One thing I could do is try to assign the result to variables of various types, e.g.:

// Compiles, so inferred type is at least Throwable.
Throwable foo = choose(new EOFException(), new FileNotFoundException());

// If this compiles, T must be Map or something that implements Map.
Map foo = choose(new HashMap(), new TreeMap());

But that's rather indirect. I'd like the compiler to tell me what type it infers for T, rather than me having to play 20 questions.

A: 

I would expect type inference to happen at the compile stage (c.f. Scala), so I'm a little confused by your question.

Java uses type erasure when implementing generics. Note that type inference is proposed for Java 7, however.

Brian Agnew
If you're downvoting, can you indicate what you disagree with, please ?
Brian Agnew
A: 

Well, given your two examples, you don't have to expect a particular type as a result. The compiler will take the most specific common type as "T", and if this "type" is an interface, then you'll have instances of annoymous classes implementing that interface (for your "foo" object).

gizmo
+3  A: 

In eclipse, hover the mouse over the method call expression. Eclipse will display the signature using the inferred type.

Edit: It appears this is indeed not always correct. For the following declarations

interface I {void foo();}
class C {}
class D extends C implements I { public void foo() {}}
class E extends C implements I { public void foo() {}}

and the expression,

java.util.Arrays.asList(new D(), new E()).get(0).foo();

the displayed inferred type is ? extends C, but the actually inferred type is ? extends C & I, as evident by the permitted access to foo. I've got no clue why eclipse displays a different type than its built-in compiler infers ...

meriton
That's perfect, thanks!
Martin C. Martin
After a little more investigation, it turns out Eclipse gives an oversimplified (i.e. wrong) answer. If I type could be multiple things (e.g. the two args in the example share many interfaces as well as a base class), Eclipse picks one, and not even the one that's actually used in the context.
Martin C. Martin
Interesting, that is indeed the case. Have provided a test case in my answer to demonstrate that. Sorry, seems I trusted eclipse too much. I'll leave my answer so others can see why it doesn't quite work.
meriton