Atom Feed SITE FEED   ADD TO GOOGLE READER

Guice punches erasure in the face!

Java 5 Type Erasure is frustrating. I'm coding along, enjoying the glorious type safety of generics. And then I try to do a little more with the Ts, and erasure shows up, "You can't do that!" I can't test an object if it really is a T. I can't inspect T.class using reflection. And I certainly can't new up a T. Yuck.

We're in a unique situation with Guice. Its type literals and injection points have complete generic information. It can follow long chains of type variables throughout an object model. In my app, I've got a Robot<T> that injects a Claw<T>. When I request a Robot<Adamantium>, Guice knows to find an adamantium claw.

And now, this type information is available to application code. I can write a Claw<T> class that actually knows what T is at runtime!

Consider GuardingList<T>, which enforces type safety at runtime:
class GuardingList<T> extends AbstractList<T> {
private final TypeLiteral<T> elementType;
private final ArrayList<T> delegate = new ArrayList<T>();

@Inject
GuardingList(TypeLiteral<T> elementType) {
this.elementType = elementType;
}

public boolean add(T t) {
checkArgument(elementType.getRawType().isInstance(t),
"Cannot add %s which is not of type %s", t, elementType);
return delegate.add(t);
}

public T get(int i) {
return delegate.get(i);
}

public int size() {
return delegate.size();
}
}
When injected, Guice applies its type knowledge to inject the correct TypeLiteral<T>. The GuardingList blows up when I add an invalid element:
  public static void main(String[] args) {
Injector injector = Guice.createInjector();

List<String> listOfString = injector.getInstance(
new Key<GuardingList<String>>() {});
listOfString.add("A");
listOfString.add("B");

/* totally unsafe, but this compiles and runs */
List<Object> rawList = (List) listOfString;

/* throws an IllegalArgumentException, since the GuardingList
knows that its elements must be Strings */
rawList.add(666);
}
Types are the natural currency of Java. Erasure is frustrating 'cause it takes them away from you at runtime. And now Guice can give 'em back.

Reify today.
awesome! thank you so very much for this feature!!! :D
I dont get the message. Guice is all about compile time type safety while you - at the end of the blog entry - seem to be happy about the fact the a List of Objects throws an IllegalArgumentException at RUNTIME? How in the world is this better to the classic ClassCastException that also happens at runtime?

I am with you about all of the advantages of Guice and compile time type safety, but I dont get why your example is putting this in a positive light...
I think his example was bad, but the usefulness of the feature is quite good: imagine having the list implementation printing an error message when it grows too big, with the error message including the type of the list (so it's clear which list gave the error). Or a cache object which uses different caching strategies based on the type of its keys, etc.
The only thing bad about the example is that Java is still stupid. The ClassCastException wouldn't happen when the element was added to the list, it would happen as some point later on when an element of the wrong type is taken out of the list and used, which would be about a million times harder to track down.
This just seems to slightly improve the chances of catching issues earlier in the runtime. It has nothing really to do with Type erasure or its downside. And the bases of this idea has little to do with Guice either. You could quiet easily see this is google collections or you own class.

I.e. the entire depedency injection framework gives you nothing extra.

Not being able todo something like

MyObject o = factory.create()

Is a much more pertinent example of the problems in type erasure
@liam: this example is admittedly simple, but this is real reification.

Guice-created types can access their type parameters. This includes types created immediately by calls into Guice via getInstance(), and types created to fulfill distant dependencies.

It'll work for arbitrary business logic classes. I predict this gives power to applications and frameworks that build on Guice.
I still dont see what this has specifically to do with Guice.
Admitidly Type information classes could be of use, but saying I should run in Guice to achieve this seems wrong. Is there some fundamental reason why it cant be achieved without the baggage?

The Type erasure issue is something that is more fundamentally floored in the Java language. I dont really know why this method was choosen, I guess some backward combatibility issues.

Although Generics have given benefits, you would have to question a lot in there implementation and the complexity wild cards have brought about.

List[String] l = Lists.newArrayList();

What more should I need to tell the compiler to provide complete Runtime and Compiletime safety? Looks like Bloch has a few things to answer for.
This feature is called 'Super Type Token' (and leveraged by Guice for their purposes).

I think it was first introduced by Neil Gafter.

The mechanism behind is the fact that the new reflection API allows to call getGenericSuperclass() on a given class instance.

So now you can come up with an anonymous class of an arbitry generic Type that gets type parametrized like so

Map<String,Integer> map = new HashMap<String,Integer>(){};

Now you could call

( (ParametrizedType) map.getClass() ).getGenericSuperclass()

and voila ... you can see all the parametrized types ...

So this feature isn't Guice specific but a feature of the 'new' Reflection API

Greetings

Mario
@mario yup, Guice leverages all of the generic stuff to make it easy. Erasure means that by default, an instance doesn't know what it's type parameters are.

The fix is to get the caller to pass these in. Usually this is clumsy, but now Guice makes it easy. Especially when you have long chains of parameterized types, like a MapReducer<T> whose field is a Mapper<T>.
Here is a similar strategy for dealing with erasure, but in Scala: http://scala-blogs.org/2008/10/manifests-reified-types.html

Scala runs on the JVM so it gets its types erased, just like in Java. Instead of using injection to re-enter the information, it allows for an invisible parameter to essentially do the injection at compile time.

Just another example of Scala fixing Java :-) Maybe this will find its way into Java 9.0 or so!
Who knows where to download XRumer 5.0 Palladium?
Help, please. All recommend this program to effectively advertise on the Internet, this is the best program!