In an example below, I like to return any type of Container from the function getInfos and from the caller side to perform map with pattern matching however I get compiler error that I cannot return Container[_]. Is there a way to return Container of any type? If not, what is the best way to approach this?
trait Info[T] {
def value: T
}
case class ContainerAInfo(value: Long) extends Info[Long]
case class ContainerBInfo(value: String, value2: String) extends Info[String]
trait Container[T] {
def info: Info[T]
}
case class ContainerA[Long](projectionInfo: ContainerAInfo)
case class ContainerB[String](projectionInfo: ContainerBInfo)
def getInfos: Seq[Container[_]] = {
Seq(
ContainerA(
projectionInfo = ContainerAInfo(1L)
),
ContainerB(
projectionInfo = ContainerBInfo("12", "12")
)
)
}
CodePudding user response:
Long and String in
case class ContainerA[Long](...)
case class ContainerB[String](...)
are not standard Long (scala.Long) and String (scala.Predef.String aka java.lang.String). You introduce new generics shadowing standard Long and String. It's better to switch on scalacOptions = "-Xlint:type-parameter-shadow" to avoid such confusion
Type Arguments and Bounds in Scala
What causes this type error in a pattern guard for matching list of tuples
Strange Error with String in Scala 2.12.7
Type parameters applied to Scala Function
I suspect ContainerA and ContainerB are supposed to extend Container, don't they? So a minimal change to your code making it compile is
case class ContainerA(info: ContainerAInfo) extends Container[Long]
case class ContainerB(info: ContainerBInfo) extends Container[String]
def getInfos: Seq[Container[_]] = {
Seq(
ContainerA(
info = ContainerAInfo(1L)
),
ContainerB(
info = ContainerBInfo("12", "12")
)
)
}
Container[_] is an existential type, a minimal supertype of all Container[T], including Container[Long], Container[String], Container[Any]
scala - Any vs underscore in generics
Understanding scala's _ vs Any/Nothing
CodePudding user response:
You can consider making the hierarchy covariant and using Seq[Container[Any]]:
trait Info [ T] {
def value: T
}
case class ContainerAInfo (value: Long) extends Info [Long]
case class ContainerBInfo (value: String, value2: String) extends Info [String]
trait Container [ T] {
def projectionInfo: Info [T]
}
case class ContainerA (projectionInfo: ContainerAInfo) extends Container [Long]
case class ContainerB (projectionInfo: ContainerBInfo) extends Container [String]
def getInfos: Seq [Container [Any]] =
Seq (
ContainerA (
projectionInfo = ContainerAInfo (1L)
), ContainerB (
projectionInfo = ContainerBInfo ("12", "12")
)
)
Though possibly it will not be that useful.
