2
votes
trait Account[T <: Account[T]]

case class BrokerAccount(total:BigDecimal) extends Account[BrokerAccount]
case class SavingsAccount(total:BigDecimal) extends Account[SavingsAccount]

Below function declaration and invocation works fine.

def foo1( xs: Array[T forSome { type T <: Account[T] }]):Array[T forSome { type T <: Account[T] }] = xs
foo1(Array(BrokerAccount(100),SavingsAccount(50)))

But below invocation gives compilation error.

def foo2( xs: List[T forSome { type T <: Account[T] }]):List[T forSome { type T <: Account[T] }] = xs
foo2(List(BrokerAccount(100),SavingsAccount(50)))

Error

Main.scala:14: error: type mismatch;
found : List[Product with Serializable with Main.Account[_ >: Main.SavingsAccount with Main.BrokerAccount <: Product with Serializable with Main.Account[_ >: Main.SavingsAccount with Main.BrokerAccount <: Product with Serializable]]]
required: List[T forSome { type T <: Main.Account[T] }] foo2(List(BrokerAccount(100),SavingsAccount(50)))

Can someone please explain me why compilation error occur in later case?

1

1 Answers

3
votes

The key to the problem is variance - you're trying to return a contravariant value in covariant position (function return type). Despite List type is covariant in its argument (trait List[+A]), this essentially means its values are contravariant (can be assigned to a List of supertypes):

val listOfSupers: List[_ >: Account[_]] = List(BrokerAccount(100), SavingsAccount(50))

What you're trying to return from the function foo2 is a complete contrary - List[_ <: Account[_]], thus the compiler error.

If instead of List you use Set there, which is invariant in its type parameter just like Array, everything will work fine.