thoughts about programming, tv-series and other geeky stuff.

Since Java introduced generics the type declarations got at lot longer. This is especially annoying when an API forces you to cast objects, like the reflection-API, the JDO-API , etc. There are plenty of APIs which requires such casts. Those casts force you to write the (obvious) type twice, for the type-declaration and the cast.

Generic Trickery

We know that for methods the generic arguments can be inferred. I already demonstrated that this can be used to rethrow checked exceptions without wrapping it, which has become one of my favorite Java utility methods. So maybe we can create something similar for casts? Well yes, it’s possible. In order to do so we just define a static cast-method. The return type and the argument type are generic. Since both are inferred by the compiler, we just introduced a ‘cast’ which automatically casts to the expected type.

// the cast now just casts to the type we write on the left
// the type is inferred
Map<String, Set<Book>> booksByTag = cast(obj);
// another example:
Object number = 1;
Integer listOfStrings = cast(number);
// JPO a bit more pleasant:
Collection<Book> result = cast(persistenceManager.newQuery(Book.class).execute());

Note that this also allows impossible casts, which are usually detected by the Java compiler. Let’s take a look at an example:

Restrict Casting

Additionally we can restrict our cast method usage. We can use the co- and contra-variance declaration for generics. Even cooler we can define relations between the generic arguments. For example we can define that the cast-target has to be a sub-type in order to be casted.

Set aSet = null;
// works, because we cast to a sub-type
HashSet<String> hashSetOfStrings = cast(aSet);
// doesn't work, because we cast to a not related type
List<String> listOfStrings2 = cast(aSet);

Compiler Differences

With such generic trickery you might hit edge cases where the compilers disagree with each other. With this cast-method there’s a edge case when you combine the inference with auto boxing. The Java-6 javac-compiler will give a compiler error when cast something to a primitive-type. The Eclipse compiler is fine with that and works as expected. With the boxed type Integer it works just fine with both compiler.

// Works with Javac and Eclipse compiler
Integer aInt = cast(number);
// Doesn't work with the Javac compiler
// Works fine with the Eclipse compiler
int aInt = cast(number);

Conclusion

I’ve demonstrated that you can define a cast-method which infers the cast target type from its usage. However this only works in some cases, loses some compiler checks and also brings some compiler edge cases differences to the surface. So it’s not really a good idea for production code.