August 22, 2007

Helping javac infer generic return types

One of my pet peeves with Java generics is that you can't pass the result of a method that returns a generic type whose bounds cannot be inferred from actual arguments directly to another method. This is particularly useful when passing an empty list obtained from Collections.emptyList() to a method:

class Test
{
   static void foo(List<String> list) {}

   public static void main(String[] args)
   {
     foo(Collections.emptyList()); // doesn't compile
   }
}


Unfortunately, that doesn't compile. It can be worked around by doing:

List<String> list = Collections.emptyList();
foo(list);


It beats me why the compiler cannot infer the appropriate type for the list returned by Collections.emptyList() in the first example above. I understand why it would fail when 'foo' has multiple overloads, but it should work for the simple case when the method resolution is unambiguous.

I recently came across an obscure (yes, ugly and unintuitive) way of getting the first example to work. It consists in telling the compiler explicitly what to bind the return type to. This is the BNF definition, per the JLS 3.0:

MethodInvocation:
   MethodName ( ArgumentList? )
   Primary . NonWildTypeArguments? Identifier ( ArgumentList? )
   super . NonWildTypeArgumentsopt Identifier ( ArgumentList? )
   ClassName . super . NonWildTypeArguments? Identifier ( ArgumentList? )
   TypeName . NonWildTypeArguments Identifier ( ArgumentList? )


And here's a concrete example:

foo(Collections.<String>emptyList());

Labels: ,