You're thinking about generics. .class files preserve a whole bunch of type information (I'm building a .class decompiler in my free time, and I'm looking at that very same data in my debugger ATM).
Even generic types are available in the Java .class file and are accessible from the reflection API. Spring for example uses this quite heavily.
Type information is present in fields and class inheritance
For example, a class like this
`class Foo implements Bar<String>`
Retains the fact that the generic type is a String.
That information is completely lost at method invocation. So a method that takes a `Bar<String>` ultimately compiles to a method that takes a `Bar` and knows nothing of the String.
To get that generic information down you have to engage in some fun tricks using either the class or field method I mentioned earlier. (Usually you do this with a second type parameter where it matters).
In JS you can only get the types by profiling.
Also it’s not really true that genetics are erased. There’s that horrible thing javac does so that the VM can support reflection for generics. I get your point though.
Overall I think C# got this one right. Generics are right there in the binaries.
bUt ActuALLy, I think the rightest right thing is to do specialization up to representation at link time (or compile time), when the whole program is available, ala MLton. Virgil does this. Of course this is not possible in a dynamic code loading environment but I only have so many fucks to give in this life.
I agree C# got this right.
I agree that doing specialization up to link time is ideal from a certain standpoint.
e.g.
class A<Y extends X> {
// in this scope, Y is known to be of at least type X,
// so, we can call methods on expressions of type Y
// that belong to type X (and not Object)
Y m() { ... }
}
Type arguments are omitted from usage sites. The technique is literally called erasure in papers and documentation. a = new A<Foo>();
f = a.m(); // should return a Foo, in bytecode returns Y
// and compiler inserts a cast from Y -> Foo
Generic code is slower in Java because of these extra casts. To get back (most of) the performance, the JVM has to inline enough methods to be able to track the types from start to finish. It can't always.
Still, the JVM JIT is faster than JS due to reasons explained in the sibling comment of the parent one.