Why does the partial function
val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
case v@Warped(Engineer(name: String)) => v.asInstanceOf[Warped[Engineer]]
}
seem to require asInstanceOf cast on RHS whilst the following does not
val engineers: PartialFunction[Crewmember, Engineer] = {
case v@Engineer(name) => v
}
sealed trait Crewmember
case class Engineer(name: String) extends Crewmember
case class Commander(name: String) extends Crewmember
case class Warped[+A <: Crewmember](v: A)
val engineers: PartialFunction[Crewmember, Engineer] = {
case v@Engineer(name) => v
}
val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
case v@Warped(Engineer(name: String)) => v.asInstanceOf[Warped[Engineer]]
}
val crew: List[Crewmember] =
List(Engineer("Geordi"), Commander("Picard"), Engineer("Scott"), Commander("Kirk"))
val warpedCrew: List[Warped[Crewmember]] =
List(Warped(Engineer("Geordi")), Warped(Commander("Picard")), Warped(Engineer("Scott")), Warped(Commander("Kirk")))
crew collect engineers
// res0: List[Engineer] = List(Engineer(Geordi), Engineer(Scott))
warpedCrew collect warpedEngineers
// res1: List[Warped[Engineer]] = List(Warped(Engineer(Geordi)), Warped(Engineer(Scott)))
Casting with asInstanceOf could be avoided like so
case Warped(eng: Engineer) => Warped(eng)
but I am wondering why does compiler not insert implicit asInstanceOf and instead types v to Warped[Crewmember]
val warpedEngineers: PartialFunction[Warped[Crewmember], Warped[Engineer]] = {
case v@Warped(Engineer(name: String)) => v
}
Error: type mismatch;
found : Warped[Crewmember]
required: Warped[Engineer]
case v@Warped(Engineer(name: String)) => v
According to SLS 8.1.3: Pattern Binders
A pattern binder @ consists of a pattern variable and a pattern . The type of the variable is the static type implied by the pattern . This pattern matches any value matched by the pattern , and it binds the variable name to that value.
A pattern implies a type if the pattern matches only values of the type .
Warped(Engineer(name))on the left inhas static type
Warped[Crewmember]because that's what you wrote in the type signatureSo if you write just
von the right it's a type mismatch.Warped(Engineer(name))on the right and on the left inlook similar but are different because they have different types. They are actually
Warped[Crewmember](Engineer(name))andWarped[Engineer](Engineer(name)). Because of covarianceWarped[Engineer]is aWarped[Crewmember]but not vice versa.How is compiler supposed to guess that it should insert
asInstanceOfhere and shouldn't for example inval x: Int = "a"?If you change the signature
then static type of
vwill beWarped[Engineer]and the code will compile.Similarly if you use typed pattern
then static type of
vwill beWarped[Engineer]and the code will compile.It seems in terms of specification pattern
v@Warped(Engineer(name))in"implies" type
Warped[Crewmember](because of the signature).