Why are Arrays invariant, but Lists covariant?
Because it would break type-safety otherwise.If not, you would be able to do something like this:
val arr:Array[Int] = Array[Int](1,2,3)val arr2:Array[Any] = arrarr2(0) = 2.54
and the compiler can't catch it.
On the other hand, lists are immutable, so you can't add something that is not Int
The difference is that List
s are immutable while Array
s are mutable.
To understand why mutability determines variance, consider making a mutable version of List
- let's call it MutableList
. We'll also make use of some example types: a base class Animal
and 2 subclasses named Cat
and Dog
.
trait Animal { def makeSound: String}class Cat extends Animal { def makeSound = "meow" def jump = // ...}class Dog extends Animal { def makeSound = "bark"}
Notice that Cat
has one more method (jump
) than Dog
.
Then, define a function that accepts a mutable list of animals and modifies the list:
def mindlessFunc(xs: MutableList[Animal]) = { xs += new Dog()}
Now, horrible things will happen if you pass a list of cats into the function:
val cats = MutableList[Cat](cat1, cat2)val horror = mindlessFunc(cats)
If we were using a careless programming language, this will be ignored during compilation. Nevertheless, our world will not collapse if we only access the list of cats using the following code:
cats.foreach(c => c.makeSound)
But if we do this:
cats.foreach(c => c.jump)
A runtime error will occur. With Scala, writing such code is prevented, because the compiler will complain.