Skip to content

Instantly share code, notes, and snippets.

@4e6
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 4e6/ba0ff9bc42fa3d8462d3 to your computer and use it in GitHub Desktop.
Save 4e6/ba0ff9bc42fa3d8462d3 to your computer and use it in GitHub Desktop.
Scala subtype check
scala> val fs = Field("string")
fs: Field[String] = Field(string)
scala> val fi = Field(1)
fi: Field[Int] = Field(1)
scala> val O = Update[Object]
O: Update[Object] = sparken.Update$$anon$1@4b41956d
// Runtime check
scala> O.update(fs, 1)
res0: sparken.Field[_] = Field(1) // Updated
scala> O.update(fi, "foobar")
res2: sparken.Field[_] = Field(1) // Not updated
// Compile time check
scala> O.updateSubtype(fs, 1)
res3: sparken.Field[Int] = Field(1) // Updated
scala> O.updateSubtype(fi, "foobar") // Compile time error
<console>:13: error: Cannot prove that Int <:< Object.
O.updateSubtype(fi, "foobar")
^
import scala.reflect.runtime.universe._
case class Field[A](value: A)
trait Update[A] {
def evA: TypeTag[A]
def update[B: TypeTag, C](f: Field[B], c: C): Field[_] = f match {
case _: Field[_] if typeTag[B].tpe <:< evA.tpe => Field(c)
case _ => f
}
// Without reflection, compile time check
def updateSubtype[B, C](f: Field[B], c: C)(implicit ev: B <:< A) =
Field(c)
}
object Update {
implicit def apply[A: TypeTag]: Update[A] =
new Update[A] { val evA = typeTag[A] }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment