Last active
February 7, 2017 03:21
-
-
Save mjhopkins/282f9971a98c2dcdad70a1dd3b5bcb57 to your computer and use it in GitHub Desktop.
Demonstrates a scenario where Scala fails to refine a type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sealed trait Role[N <: Entity] | |
case object VIP extends Role[Customer] | |
case object Shopper extends Role[Customer] | |
case object Manager extends Role[Staff] | |
case object Employee extends Role[Staff] | |
sealed trait Entity | |
case class Customer(name: String) extends Entity | |
case class Staff(id: Int) extends Entity | |
sealed trait RolePair { | |
type N <: Entity | |
val role: Role[N] | |
val entity: N | |
} | |
object RolePair { | |
def apply[M <: Entity](r: Role[M], n: M): RolePair = new RolePair { | |
type N = M | |
val role: Role[N] = r | |
val entity: N = n | |
} | |
def unapply(rp: RolePair): Some[(Role[rp.N], rp.N)] = Some((rp.role, rp.entity)) | |
// Scala 2 version (broken in 2.11, 2.12) | |
// def unapply(rp: RolePair): Some[(Role[N], N)] forSome { type N <: Entity } = Some((rp.role, rp.entity)) | |
} | |
object RolePairTest { | |
def main(args: Array[String]): Unit = { | |
val roles: List[RolePair] = List( | |
RolePair(Manager, Staff(1)), | |
RolePair(Shopper, Customer("Max")), | |
RolePair(Employee, Staff(2)), | |
RolePair(Employee, Staff(3)), | |
RolePair(VIP, Customer("Lucy")) | |
) | |
// The following hould be a List[Customer], but it is only a List[RolePair#N] under dotty (List[Entity] under 2.11, 2.12) | |
// This worked in 2.10 but is broken in 2.11 and dotty | |
val vips = | |
roles collect { | |
case RolePair(VIP, customer) => customer | |
} | |
vips foreach { vip => println(vip.name) } | |
val vipsAndManagers = // Should be a List[Customer | Manager], but it is only a List[RolePair#N] | |
roles collect { | |
case RolePair(VIP, customer) => customer | |
case RolePair(Manager, manager) => manager | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note that I can't even call
.name
within the body of the case statement on line 47.