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 (becauseString
is 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 ?
Fruit
as an upper bound to the parameterB
inBasket.addAll
method (addAll[B >: A <: Fruit]...
). – Peter Neyens