Search code examples
javatypescompiler-errorscompilationtype-erasure

Would removing Java type erasure help to catch more errors at compile time?


List<String> stringList = new ArrayList<>();
List rawList = stringList;
rawList.add(10);

So the above code compiles with a warning, but breaks at runtime. This was presented as one of the cases where removing type erasure in Java would have a positive effect (although I understand on balance we will never remove it).

My confusion is, we do type checking before type erasure occurs. So how can deciding not to do some later step in the compilation process help us to find problems we previously couldn't find?

Case 1:

  1. do type checking, fail to find the error above
  2. do type erasure

Case 2:

  1. do type checking, manage to find the error above

But if that's possible, why not just do case 3:

  1. do type checking, manage to find the error above
  2. do type erasure

I hope it's clear what I don't understand.


Solution

  • My confusion is, we do type checking BEFORE type erasure occurs...

    In this particular example, you are using raw types, so there is no type-checking on the type parameter either.

    Before generics were added to Java, there were not type parameters in the code, but people still want code from back then to compile, so some parts of type-checking has to be disabled for raw types.

    Without type erasure, raw types, which are the erased forms of parameterised types, wouldn't exist either, so the question is moot.


    You talk about "removing type erasure" as if type erasure is some additive feature to the language. It is not. The compiler is just doing what it has always been doing since before generics exist - not emitting generic type information of local variables into the class file, because the JVM doesn't support generic types.

    What would change if the JVM did support generic types, is that exceptions could be thrown at runtime much earlier. Suppose you are casting some variable of type Object to a List<String>. Suppose the variable actually stores a List<Integer>. The JVM can check that the cast is invalid at runtime and throw an exception right there where the cast is. In reality the JVM cannot do this, and will throw an exception only when you try to get a String out of that List<Integer>, which is potentially much later.