I am learning the concept of type variance and bounds in scala and how to use them. I came across the below question on stack overflow where one of the solutions mentioned how to prevent scala from generalizing the types.
Below is the code posted in the solution. In the below code, How does adding a new type parameter C help? I understand how B is constrained ( as a supertype of A and subtype of Fruit). But I am completely lost as to what C does here. Why should it be Super type of A. Why does the implicit evidence require B to be subtype of C?
And why there is an irrelevant error when adding List of Orange object that Fruit is not subtype of Banana. Can someone please explain this?
I am guessing to satisfy the first constraint, Orange object is inferred as Fruit object but lost after that as to why it says Fruit is not a subtype of Banana.
case class Banana() extends Fruit
defined class Banana
case class Orange() extends Fruit
defined class Orange
case class Basket[+A <: Fruit](items: List[A]) {
// ...
def addAll[B >: A <: Fruit, C >: A](newItems: List[B])(implicit ev: B <:< C): Basket[B] =
new Basket(items ++ newItems)
// ...
}
defined class Basket
val bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))
bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))
bananaBasket.addAll(List(Orange())) // not accepted
Main.scala:593: Cannot prove that Product with Serializable with cmd27.Fruit <:< cmd47.Banana.
bananaBasket.addAll(List(Orange()))