From List[+T]
I understand a list of dogs is also a list of animals which aligns perfectly with the intuition. From def :: [B >: A](elem: B): List[B]
I understand I can add an animal (B
, less specific) to a list of dogs (A
, more specific) and will get back a list of animals. This aligns with the intuition as well. So basically List
is good.
From Array[T]
I understand an array of dogs is not (could not be used in place of a) an array of animals which is rather counterintuitive. An array of dogs is indeed an array of animals as well but obviously Scala disagrees.
I was hoping someone intuitively explain why Array
in invariant, preferably in terms of dogs (or cats).
There is Why are Arrays invariant, but Lists covariant? but I'm looking for a more intuitive explanation that doesn't (heavily) involve the type system.
Related to Why is Scala's immutable Set not covariant in its type?
The reason is pretty simple. Is because Array
is a mutable collection. Remember there is a very easy rule of thumb about variance.
If it produces something it can be covariant.
If it consumes something it can be contravariant.
That is why Functions
are contravariant on input and covariant on output.
Because Arrays
are mutable they are in fact both producers and consumers of something, so they have to be invariant.
Let me show why it has to be like that with a simple example.
// Assume this compiles, it doesn't.
final class CovariantArray[+A] (arr: Array[A]) {
def length: Int = arr.length
def apply(i: Int): A = arr(i)
def update(i: Int, a: A): Unit = {
arr(i) = a
}
}
sealed trait Pet
final case class Dog(name: String) extends Pet
final case class Cat(name: String) extends Pet
val myDogs: CovariantArray[Dog] = CovariantArray(Dog("Luna"), Dog("Lucas"))
val myPets: CovariantArray[Pet] = myDogs // Valid due covariance.
val myCat: Cat = Cat("Milton")
myPets(1) = myCat // Valid because Liskov.
val myDog: Dog = myDogs(1) // Runtime error Cat is not Dog.
You can reproduce this error in Java using normal Arrays
, Scala will simply not let you compile.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With