Overcoming type erasure in Scala

class Foo[T] {
val foo: T
}
class Bar[T <: Something] {
val bar: T
}
class Foo {
val foo: Object
}
class Bar {
val bar: Something
}
object Extractor {
def extract[T](list: List[Any]) = list.flatMap {
case element: T => Some(element)
case _ => None
}
}

val list = List(1, "string1", List(), "string2")
val result = Extractor.extract[String](list)
println(result) // List(1, string1, List(), string2)
import scala.reflect.ClassTagobject Extractor {
def extract[T](list: List[Any])(implicit tag: ClassTag[T]) =
list.flatMap {
case element: T => Some(element)
case _ => None
}
}
val list: List[Any] = List(1, "string1", List(), "string2")
val result = Extractor.extract[String](list)
println(result) // List(string1, string2)
// def extract[T](list: List[Any])(implicit tag: ClassTag[T]) =
def extract[T : ClassTag](list: List[Any]) =

If an implicit value of type u.ClassTag[T] is required, the compiler will make one up on demand.

Compiler tries to turn unchecked type tests in pattern matches into checked ones by wrapping a (_: T) type pattern as ct(_: T), where ct is the ClassTag[T] instance.

case element: T => Some(element)
case (element @ tag(_: T)) => Some(element)
case Foo(p, q) => // we can only reference parameters via p and q
case f @ Foo(p, q) => // we can reference the whole object via f
val list: List[List[Any]] = List(List(1, 2), List("a", "b"))
val result = Extractor.extract[List[Int]](list)
println(result) // List(List(1, 2), List(a, b))
import scala.reflect.runtime.universe._object Recognizer {
def recognize[T](x: T)(implicit tag: TypeTag[T]): String =
tag.tpe match {
case TypeRef(utype, usymbol, args) =>
List(utype, usymbol, args).mkString("\n")
}
}

val list: List[Int] = List(1, 2)
val result = Recognizer.recognize(list)
println(result)
// prints:
// scala.type
// type List
// List(Int)

Universe provides a complete set of reflection operations which make it possible for one to reflectively inspect Scala type relations, such as membership or subtyping.

val list: List[Int] = List(1, 2)
val result = Recognizer.recognize(list)
import scala.reflect.runtime.universe._abstract class SomeClass[T] {

object Recognizer {
def recognize[T](x: T)(implicit tag: WeakTypeTag[T]): String =
tag.tpe match {
case TypeRef(utype, usymbol, args) =>
List(utype, usymbol, args).mkString("\n")
}
}

val list: List[T]
val result = Recognizer.recognize(list)
println(result)
}

new SomeClass[Int] { val list = List(1) }
// prints:
// scala.type
// type List
// List(T)
import scala.reflect.classTag
import scala.reflect.runtime.universe._

val ct = classTag[String]
val tt = typeTag[List[Int]]
val wtt = weakTypeTag[List[Int]]

val array = ct.newArray(3)
array.update(2, "Third")

println(array.mkString(","))
println(tt.tpe)
println(wtt.equals(tt))

// prints:
// null,null,Third
// List[Int]
// true

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store