Jatin
Jatin

Reputation: 31754

:: method in List - contravariant argument type

A simple question. The method :: of class immutable List is defined as:

sealed abstract class List[+A] ...

def ::[B >: A](x: B): List[B]

Suppose say I have:

class Fruit
class Mango extends Fruit
scala> val d:List[Fruit] = List.empty[Fruit]
d: List[Fruit] = List()

scala> new Mango :: d
res5: List[Fruit] = List(Mango@272d6774)

Now I am confused here. As per :: declaration, the argument type should be contravariant. i.e. in this case any class that >: Fruit (I understand why it is made that way). But what I dont get is, Mango <: Fruit, so why doesn't the compiler throw error?

Upvotes: 0

Views: 104

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170919

In the line

new Mango :: d

you expect the compiler to reason: "new Mango has type Mango and d has type List[Fruit], so List[Fruit].::(Mango) needs to typecheck, which it doesn't". In this case it would indeed be an error.

But in fact, it reasons differently: "I need new Mango :: d to typecheck, so new Mango must have some type B such that B :> Fruit. Is there such a B? Yes, B = Fruit." So there is no error.

Upvotes: 3

Dylan
Dylan

Reputation: 13922

You would still be able to add the Mango to d even if List was invariant, simply because Mango is still a Fruit. Think about it in terms of a plain old java list:

val d = new java.util.ArrayList[Fruit]
d.add(new Mango)

So the contravariance doesn't restrict your ability to add subtypes - it enables you to add supertypes and get a compiler-checked list type back from it:

val d: List[Fruit] = Nil
val a: List[Plant] = new Carrot :: d

Upvotes: 5

Related Questions