Type erasure is evil in java generics because types are reified in java. Reified types are an expectation of java programmers, and failing to re-ify generic types creates an un-natural limitation in the system as a whole.
In many other langauges, there is no expectation of reification and type erasure is a natural consequence of the compilation process.
A measure of reification is required to support runtime detection of bad down-casts. This is
present in C#/Java in the form of
InvalidCastException and in C++ is supported via
It seems tragic that supporting downcasts should limit the type system's design in such a pervasive manner--reification is quite expensive.
- are downcasts really that important?
- are safe downcasts really that important?
- is knowing the type of an object at runtime really that important?
- Haskell/ML say no to all.
- Java says yes to all.
- C++ says yes to (1) and possibly (1) and (2) depending on who you ask and how annoying they find rtti to be.
- Scala has downcasting operators, but might not actually need them.
- In C#, I very almost never downcast unless forced into it by a library (e.g. WeakReference). That said, I often need to jump through hoops to avoid it. Less pedantic developers seem to prefer downcasting to generics.
Runtime type information is a commonly used escape hatch in JVM/CLR environments.
- When type-level encodings get too gnarly, you can fall back on 'object'
- You can fling objects through many layers of unsuspecting, non-generic code, and then go hunting for interfaces or base classes in a low level place
- Checking things dynamically is often far easier than encoding the same things at the type level.
- Dynamic systems are more honest and dramatically simpler to reason about because values do not change behavior based on static positioning.