Skip to content

Instantly share code, notes, and snippets.

@manjuraj
Last active March 24, 2017 07:05
Show Gist options
  • Save manjuraj/ef1a3aa7435a8fd45f35 to your computer and use it in GitHub Desktop.
Save manjuraj/ef1a3aa7435a8fd45f35 to your computer and use it in GitHub Desktop.
TypeTags and Manifest
// References
// - http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html
// - http://stackoverflow.com/questions/12218641/scala-what-is-a-typetag-and-how-do-i-use-it
// - http://blogs.atlassian.com/2012/12/scala-and-erasure/
// - http://www.scala-blogs.org/2008/10/manifests-reified-types.html
// - http://stackoverflow.com/questions/3587286/how-does-scalas-2-8-manifest-work
// - http://stackoverflow.com/questions/3213510/what-is-a-manifest-in-scala-and-when-do-you-need-it
//
// Why Manifest? - used to access type parameters of generics at runtime
// - reification and erasure
// - erasure: type parameter of a generic type is forgotten/erased at runtime.
// So, a List[String] - List parameterized by type String "forgets" that
// it has been parameterized by String once it has been compiled
// - reification: opposite of erasure, type is remembered at runtime
//
class X[T](val x: T)
class Y[Int](val y: Int) extends X(y)
class Z[String](z:String) extends X(z)
scala> val y = new Y(3)
y: Y[Int] = Y@5a4491a1
scala> val z = new Z("3")
z: Z[String] = Z@23f35247
scala> z.isInstanceOf[X[Int]]
<console>:11: warning: fruitless type test: a value of type Z[String] cannot also be a X[Int] (but still might match its erasure)
z.isInstanceOf[X[Int]]
^
res0: Boolean = true
//
// Use Manifest as an alternative to passing around java.lang.Class<T> objects
//
// To use Manifest, simply add add an implicit scala.reflect.Manifest[T]
// parameter to your method
//
// Use -Xprint:erasure
//
def name[T](implicit m: Manifest[T]) = m.toString
scala> name[String]
res3: String = java.lang.String
scala> name[String => Int]
res5: String = scala.Function1[java.lang.String, Int]
//
// From Predef.scala
// - https://github.com/scala/scala/blob/v2.10.3/src/library/scala/Predef.scala#L124
//
def manifest[T](implicit m: Manifest[T]) = m
scala> manifest[String].runtimeClass
res10: Class[_] = class java.lang.String
// subtype <:< and supertype >:> of one manifest wrt to another
scala> manifest[String] <:< manifest[AnyRef]
res17: Boolean = true
scala> manifest[String] >:> manifest[AnyRef]
res18: Boolean = false
def foo[T](x: List[T])(implicit m: Manifest[T]): Unit = {
if (m <:< manifest[String])
println("Hey, this list is full of strings")
else
println("Non-stringy list")
}
//
// A TypeTag is completely compiler-generated, that means that the compiler
// creates and fills in a TypeTag when one calls a method expecting such
// a TypeTag.
//
// There exist three different forms of tags:
// - scala.reflect.ClassTag
// - scala.reflect.api.TypeTags#TypeTag
// - scala.reflect.api.TypeTags#WeakTypeTag
//
// ClassTag substitutes ClassManifest whereas TypeTag is more or less the replacement for Manifest.
//
import scala.reflect._
import scala.reflect.runtime.universe._
def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*)
scala> createArr(1,2,3)
res14: Array[Int] = Array(1, 2, 3)
scala> createArr("a", "b", "c")
res15: Array[String] = Array(a, b, c)
scala> typeTag[List[Int]]
res16: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]]
scala> typeOf[List[Int]]
res17: reflect.runtime.universe.Type = scala.List[Int]
scala> res16.tpe =:= res17
res19: Boolean = true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment