Thursday, February 08, 2007

When generic type inference fails

99% of the time, using generics is perfectly natural and pleasurable. The other 1%, it can be downright humbling.

Look at the signature of Arrays.asList:

public static <T> List<T> asList(T... a)

Going to take in an array of type T, and return a List containing the same type. But what is T? The parameter "a" is just a set of parameters the caller may have just defined in-place - with no explicit declaration of T. This is only a problem when the varargs passed in are of diverse types:

Arrays.asList(new Thing<Integer>(), new Thing<String>(), new Thing<String>());

In this case, the compiler must find the lowest common denominator type. Unfortunately, with the eclipse compiler at least, that's a tad insane - it would decide the common type is this:

Thing<? extends Object&Comparable<?>&Serializable>>

Yuck! It's true, that in a vacuum, there's not much else the compiler can do. But what about when I give it more info?

public List<Thing>> getThings() {
  return Arrays.asList(new Thing<Integer>(), new Thing<String>(), new Thing<String>());

The compiler complains that it can't convert its insane type to what would appear to be a proper "super" type: Thing. It doesn't seem to me the compiler is taking advantage of all the info I'm giving it. To be fair, I'm sure there are tons of situations where the compiler has no additional context to take advantage of.

However, there's hope. In his post Java 7 Wish List , the author describes a way (which is in Java 5, btw) to give the compiler more of a nudge:

Arrays.<Thing<?>>asList(new Thing<Integer>(), new Thing<String>());

Hey, it aint pretty, but my only guess to the alternative is a bit too verbose:
List<Thing> things = new ArrayList<Thing>();
things.add(new Thing<Integer>());
things.add(new Thing<String>());

Actually, you CAN cast:

(List<Thing<?>>)Arrays.asList(new Thing<Integer>(), new Thing<String>(), new Thing<String>());

But this works only on eclipse, not javac. Plus, doesn't it feel a little to ironic to add a cast to accomodate generics :)

PS. Dear Google programmers, please use your 15% time to make it a lot easier to add code snippets to blog entries.

No comments: