Friday, November 14, 2014

Type System in Java

Unified type system. In a unified type system, all types including primitive types inherit from a single root type. For example, C# is unified typed, as every type in C# inherits from the Object class. Java has several primitive types that are not objects. However, Java provides wrapper object types that exist together with the primitive types, so developers can use either the wrapper object types or the simpler non-object primitive types.

Type erasure. (to be completed later)

Generic types. Generics have been available in Java since J2SE 5.0 was released in 2004. Generics allow for parameterized types and hence allow the compiler to enforce type safety. For example, an instance of the Vector class can be declared to be a vector of strings, written as Vector<String>. To avoid major changes to the Java runtime environment, generics are implemented using type erasure. This amounts to removing the additional type information and adding casts wherever required. For example, there is no way to distinguish between a List<String> and a List<Long> at runtime. Since JVM doesn't track the type arguments of a generic class in the bytecode, both of them are of type List at runtime.

Arrays. Java’s arrays are parameterized types written in a form different from the generic types. For example, the array type String[] is analogous to the vector type Vector<String>. On the other hand, Java arrays are not subject to type erasure like generic types are, and this leads to inconsistency in the handling of arrays and generic types. One consequence of this is that the following code will not compile:
class Test<T> {
  public Vector getVector(){ return new Vector<T>(); } // ok
  public T[] getArray(){ return new T[10]; } // compile-time error
}
Since arrays don’t support type erasure, method getArray needs the type information of T to create the array. However, as Java generics are implemented using type erasure, the parameterized type T does not exist at runtime. Hence, the compiler cannot assign a type to the array and thus will raise a "generic array creation" error.

Type parameters. (to be completed later)

Type inference. Java doesn't support type inference for variable assignments. Hence, it requires that programmers declare the types they intend a method or function to use. However, it is not true that Java doesn't have type inference. Indeed, recent versions of Java supports type inference when using generics. In Java 7, one can get some additional type inferencing when instantiating generics like so
Map<String, String> foo = new HashMap<>();
Java is smart enough to fill in the blank angle brackets for us. Moreover, we get type inference in Java 8 as a part of lambda expressions. For example, consider
List<String> names = Arrays.asList("Tom", "Dick", "Harry");
Collections.sort(names, (first, second) -> first.compareTo(second));
The Java compiler can infer from the signatures Collections#sort(List<T>, Comparator<? super T>) and Comparator#compare(T o1, T o2) that first and second should be a String, allowing the programmer to omit the type declarations in the lambda expression.

The reason why Java doesn't allow type inference for non-generic types seems to be because of  its design philosophy. That is, programmers should write things explicitly to make sure that the compiler has the same understanding of the code as them do. Besides, Java was originally aimed at programmers coming from C++, Pascal, or other mainstream languages that did not have it. Thus, type inference was probably not supported due to the principle of least surprise.

No comments:

Post a Comment