Showing posts with label type system. Show all posts
Showing posts with label type system. Show all posts

18 May 2019

Thoughts on Type Variance


in Java arrays are covariant (can be assigned to an array of supertype)

Integer[] arr = {1, 2, 3};
Object[] objArr = arr; // allowed because of being covariant
objArr[0] = "Hello"; // runtime error: ArrayStoreException

But it comes at a cost that, it might fail at runtime (as in the last line)

in Kotlin, arrays are invariant:

val arr = arrayOf(1, 2, 3)
val objArr: Array<Any> = arr // compilation error

So, invariant, doesn't consider List<Integer> to substitue List<Object> nor vice versa,

However, covariant consider List<Integer> to substitue List<Object>, but not vice versa.
And contravriant consider List<Object> to substitude List<Integer>, but not vice versa.


in Kotlin, Lists (immutable lists) are covariant, the following works:
val list = listOf(1, 2, 3)
val objList: List<Any> = list

because Lists are immutable, we can't fail as in the Java array case.

in contravariant, the super type can substitute the subtype (might seems illogical at first),
but look at this (fiction example):

operateOnIntegers(Integer i) {
i.setValue(50)
}

Number n = 30
operateOnIntegers(n)

because operateOnIntegers expected a narrower type than the passed one (expects Integer and passed Number),
it will never write a value into it that exceeds its limits.



22 January 2015

Two notes about Java Generic Types (Type Covariance and Type erasure)

Java Generics have two characteristics that are important when working with generics of Java.

The first one is the most important and most well-known than the other, the second is less known.

1. Generics types are not Covariant:

All of us knows that List<String> cannot substitute List<Object>; however String[] can substitute Object[]

This prevent error in Generics that happens in case of arrays.

String[] sArr = new String[] {"Hello"};
Object[] oArr = sArr;
oArr[0] = 10; // << Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer

However in case of Generic types, such error is being caught  at compile time, and this is because Type Parameters (Generics) doesn't allow type covariance.

Example:

List<String> sList = new ArrayList<>();
List<Object> oList = sList; // Type mismatch: cannot convert from List<String> to List<Object>

oList.add(10);

2.  Type parameters is being removed in generated byte code (Called Type erasure).

This is why you cannot say: T.class

Quote: 
When you compile some code against a generic type or method, the compiler works out what you really mean (i.e. what the type argument for T is) and verifies at compile time that you're doing the right thing, but the emitted code again just talks in terms of java.lang.Object - the compiler generates extra casts where necessary. At execution time, a List<String> and a List<Date>are exactly the same; the extra type information has been erased by the compiler.