I have been trying to push my understanding of Scala a little bit further lately and I cannot really figure out some things about covariant/contravariant type parameters.
Let's say I have a class called Basket as follows :
class Basket[+A <: Fruit](items: List[A]) {
// ...
def addAll[B >: A <: Fruit](newItems: List[B]): Basket[B] =
new Basket(items ++ newItems)
// ...
}
and some classes like this:
trait Fruit
class Banana extends Fruit
class Orange extends Fruit
I know for sure that these assertions are correct :
Basket[Fruit]can be instantiatedBasket[String]cannot be instantiated (becauseStringis not a subtype ofFruit)Basket[Banana]is a subtype ofBasket[Fruit]Basket[Orange]is a subtype ofBasket[Fruit]This code:
val bananaBasket: Basket[Banana] = new Basket(List(new Banana, new Banana)) bananaBasket.addAll(List(new Orange))
will return a Basket[Fruit]
This code:
val bananaBasket: Basket[Banana] = new Basket(List(new Banana, new Banana)) bananaBasket.addAll(List(new Banana))
will return a Basket[Banana]
What I do not understand is how the B >: A affects the return type of the method .. Why when I add an Orange the return type become Basket[Fruit] and when I add a Banana, it stays a Basket[Banana] ? Does it look for the "lowest" common super-type ?