In an earlier post about generics I described the limited impact of type erasure. Trying to describe that type erasure was more of a developer issue and less of a platform. Although I still agree with that statement, I want to show a case that adds some nuance to that statement.

Let's assume we are trying to implement something similar to the adapter pattern. We have a very simple Adaptable interface:

public interface Adaptable {
	<AdapterType> AdapterType adapt(Class<AdapterType> adapterType);
}

The interface is simple enough and we can implement this mostly safely. For example this adaptable collection.:

public interface Adaptable {
public class AdaptableCollection<Type> extends LinkedList<Type>
		implements Adaptable {
	public <AdapterType> AdapterType adapt(Class<AdapterType>
			adapterType) {
		AdapterType result;
		if (Set.class.equals(adapterType)) {
			result = adapterType.cast(new HashSet<Type>(this));
		} else {
			result = null;
		}
		return result;
	}
}

Now this actually looks fine. But it isn't. This is where type erasure may bite you. the simple fact is that the adapterType parameter has no type information.

Let's look at a usage example where it feels allright:

Set<String> set = collection.adapt(Set.class);
Assert.assertTrue(set.contains("Test Value"));
Assert.assertTrue(set.contains("Other Value"));

Anybody trying to reconstruct this in an editor will quickly notice that this will give a warning. Which it does fairly, this cannot be done safely. We can see this in the example that feels very wrong:

Set<Integer> set = collection.adapt(Set.class);
Assert.assertTrue(set.add(42));
Assert.assertTrue(set.contains("Other Value"));

This compromises the set, since it contains non integers. The complete test can be found here.

We can easily see that this (wrong) application of the adapter pattern poses some problems. Unless we building a flexible extensible framework, this should not be a problem. In which case, modifying the design should solve the problem. But for those of us that do have such challenges, then (and perhaps only then) this might be a serious issue. Although in many cases developer stupidity (may it be our own) is always an option.

Untill we get some form of generics where we can define these at runtime, we cannot successfully implement the interface safely. But there is some hope. Firstly, the compiler showing a warning is a sign that this indeed is not safe, any developer should be alert for this and think twice about what they are doing. For example, by providing source documentation of reasoning and guarantees. Secondly, it seems that Oracle has the courage to do something Sun never could, break backwards compatibility. Kudos to them, I for one am looking forward to seeing it done!