Last active
March 24, 2017 07:05
-
-
Save manjuraj/ef1a3aa7435a8fd45f35 to your computer and use it in GitHub Desktop.
TypeTags and Manifest
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
// 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