Isn't type erasure just a rather limited subclass of compiler optimization, and as such comes "for free" without having to explicitly code for it? The compiler frontend can leave in all type checks, having most of them can be removed by the optimizer, the same way you can remove any sort of redundant check (a default case in a switch statement over an enumeration, etc, etc)
That being said, general type erasure can have (massive) problems. Look at Java.
I'd say Java's type erasure has on the whole been massively successful (and it's allowed integration with e.g. Scala that a more reified type system might make difficult). What do you see as wrong with it?
For example, having to use a varargs hack just to make a T[] (that's an array of a a generic type).
Or not being able to call T.class
Or not being able to use instanceof T.
Or having a Object[] that crashes at runtime when you try to put an Object in it.
Or not being able to overload a method based on if it's passed a List<Foo> or List<Bar>. (Also applies to interfaces like Comparable, etc. There's no good way of going "this is a Comparable<Foo> and a Comparable<Bar>, but not a Comparable<Baz>.)
Or for that matter, trying to pass an int[] to something that expects an Integer[], or vice versa.
Or for that matter, someone passing in a List into your parameter expecting List<Foo> and crashing at runtime because it actually was a List<Bar>.
Introspection like this usually is a hack around (1) having a weak type system (2) using objects wrong. That said, T.class and instanceOf work perfectly fine in Haskell and such, because of the lack of inheritance in the OOP sense. Instead, they just say "if you want to get a type, implement the Typeable interface, which has a method that returns the Type". In other words, if you want it, do it manually, with the added benefit that there is 0 cost, memory or otherwise interfaces when they aren't used.
Really, a quote I heard once: "Java is like a strawman built specially by people who want to argue against using strong type systems."
It is ugly but you can make many of that things making all constructors request a paramter Class<T> cls.
One thing you learn using java is not moving arrays around.
The comparator stuff is true.
Make the compiler to fail if you pass raw classes. A List is not a List<Foo> and in some cases is not a List<?> (where List is a class of <T extends Foo>).
What I miss is some kind of self type, or "return this", I do not know how to tell it. Imagine a imaginary class A:
this aMethod() {
stuff();
return this;
)
This aMethod returns an A when invoked on an A instance or a B, B extends A, if is a B instance. Handy for builders and fluid apis:
Which doesn't help in the case I was discussing, namely when you want a generic array. As in: generic. Not specific.
You end up having to use a collection, which ends up with an order of magnitude more memory usage than an array in the case where you want to store characters. (char is the worst case. But all primitives are pretty bad in that regard.)
That being said, general type erasure can have (massive) problems. Look at Java.