Using scala 2.12.8 this would not compile without a cast:
trait Content
case object A extends Content
case class B(i: Int) extends Content
def asList[C <: Content](content: C): List[C] = content match {
case A => List(A) // compiles
case b: B => List(b) // does not compile
}
type mismatch;
found : b.type (with underlying type Playground.this.B)
required: C
Here's a Scastie link to the problem: https://scastie.scala-lang.org/JIziYOYNTwKoZpdCIPCvdQ
Why is working for the case object and not for the case class? How can I make it work for the case class?
The first answers made me realize I oversimplified my problem, here's an updated version :
sealed trait Content
case object A extends Content
final case class B(i: Int) extends Content
sealed trait Container[+C <: Content]
case class ContainerA(content: A.type) extends Container[A.type]
case class ContainerB(content: B) extends Container[B]
object Container {
def apply[C <: Content](content: C): Container[C] = content match {
case A => ContainerA(A) // compiles
case b: B => ContainerB(b) // does not compile
}
}
Scastie link: https://scastie.scala-lang.org/TDlJM5SYSwGl2gmQPvKEXQ
C cannot be a subtype of B since B is final.
C cannot be a subtype of B since B is final.
Wrong!
Singleton types of B
instances are subtypes of B
:
val b = B(0)
val container: Container[b.type] = Container[b.type](b)
Since ContainerB
doesn't extend Container[b.type]
, it can't be returned by the last line. And it can't be changed so that it does;
case class ContainerB(content: B) extends Container[content.type]
is not legal in Scala.
Null
is also a subtype of B
and you can create a similar example. And so are refinement types like B { type T = Int }
.
Other subtypes which are probably irrelevant because they don't have instances: Nothing
, compound types like B with Iterable[Int]
...