Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>A <code>TypeTag</code> solves the problem that Scala's types are erased at runtime (type erasure). If we wanna do</p> <pre><code>class Foo class Bar extends Foo def meth[A](xs: List[A]) = xs match { case _: List[String] =&gt; "list of strings" case _: List[Foo] =&gt; "list of foos" } </code></pre> <p>we will get warnings:</p> <pre><code>&lt;console&gt;:23: warning: non-variable type argument String in type pattern List[String]↩ is unchecked since it is eliminated by erasure case _: List[String] =&gt; "list of strings" ^ &lt;console&gt;:24: warning: non-variable type argument Foo in type pattern List[Foo]↩ is unchecked since it is eliminated by erasure case _: List[Foo] =&gt; "list of foos" ^ </code></pre> <p>To solve this problem <a href="http://www.scala-lang.org/api/current/index.html#scala.reflect.Manifest" rel="noreferrer">Manifests</a> were introduced to Scala. But they have the problem not being able to represent a lot of useful types, like path-dependent-types:</p> <pre><code>scala&gt; class Foo{class Bar} defined class Foo scala&gt; def m(f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar]) = ev warning: there were 2 deprecation warnings; re-run with -deprecation for details m: (f: Foo)(b: f.Bar)(implicit ev: Manifest[f.Bar])Manifest[f.Bar] scala&gt; val f1 = new Foo;val b1 = new f1.Bar f1: Foo = Foo@681e731c b1: f1.Bar = Foo$Bar@271768ab scala&gt; val f2 = new Foo;val b2 = new f2.Bar f2: Foo = Foo@3e50039c b2: f2.Bar = Foo$Bar@771d16b9 scala&gt; val ev1 = m(f1)(b1) warning: there were 2 deprecation warnings; re-run with -deprecation for details ev1: Manifest[f1.Bar] = Foo@681e731c.type#Foo$Bar scala&gt; val ev2 = m(f2)(b2) warning: there were 2 deprecation warnings; re-run with -deprecation for details ev2: Manifest[f2.Bar] = Foo@3e50039c.type#Foo$Bar scala&gt; ev1 == ev2 // they should be different, thus the result is wrong res28: Boolean = true </code></pre> <p>Thus, they are replaced by <a href="http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.TypeTags" rel="noreferrer">TypeTags</a>, which are both much simpler to use and well integrated into the new Reflection API. With them we can solve the problem above about path-dependent-types elegantly:</p> <pre><code>scala&gt; def m(f: Foo)(b: f.Bar)(implicit ev: TypeTag[f.Bar]) = ev m: (f: Foo)(b: f.Bar)(implicit ev: reflect.runtime.universe.TypeTag[f.Bar])↩ reflect.runtime.universe.TypeTag[f.Bar] scala&gt; val ev1 = m(f1)(b1) ev1: reflect.runtime.universe.TypeTag[f1.Bar] = TypeTag[f1.Bar] scala&gt; val ev2 = m(f2)(b2) ev2: reflect.runtime.universe.TypeTag[f2.Bar] = TypeTag[f2.Bar] scala&gt; ev1 == ev2 // the result is correct, the type tags are different res30: Boolean = false scala&gt; ev1.tpe =:= ev2.tpe // this result is correct, too res31: Boolean = false </code></pre> <p>They are also easy to use to check type parameters:</p> <pre><code>import scala.reflect.runtime.universe._ def meth[A : TypeTag](xs: List[A]) = typeOf[A] match { case t if t =:= typeOf[String] =&gt; "list of strings" case t if t &lt;:&lt; typeOf[Foo] =&gt; "list of foos" } scala&gt; meth(List("string")) res67: String = list of strings scala&gt; meth(List(new Bar)) res68: String = list of foos </code></pre> <p>At this point, it is extremely important to understand to use <code>=:=</code> (type equality) and <code>&lt;:&lt;</code> (subtype relation) for equality checks. Do never use <code>==</code> or <code>!=</code>, unless you absolutely know what you do:</p> <pre><code>scala&gt; typeOf[List[java.lang.String]] =:= typeOf[List[Predef.String]] res71: Boolean = true scala&gt; typeOf[List[java.lang.String]] == typeOf[List[Predef.String]] res72: Boolean = false </code></pre> <p>The latter checks for structural equality, which often is not what should be done because it doesn't care about things such as prefixes (like in the example).</p> <p>A <code>TypeTag</code> is completely compiler-generated, that means that the compiler creates and fills in a <code>TypeTag</code> when one calls a method expecting such a <code>TypeTag</code>. There exist three different forms of tags:</p> <ul> <li><a href="http://www.scala-lang.org/api/current/index.html#scala.reflect.ClassTag" rel="noreferrer">scala.reflect.ClassTag</a></li> <li><a href="http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.TypeTags$TypeTag" rel="noreferrer">scala.reflect.api.TypeTags#TypeTag</a></li> <li><a href="http://www.scala-lang.org/api/current/scala-reflect/index.html#scala.reflect.api.TypeTags" rel="noreferrer">scala.reflect.api.TypeTags#WeakTypeTag</a></li> </ul> <p><code>ClassTag</code> substitutes <code>ClassManifest</code> whereas <code>TypeTag</code> is more or less the replacement for <code>Manifest</code>.</p> <p>The former allows to fully work with generic arrays:</p> <pre><code>scala&gt; import scala.reflect._ import scala.reflect._ scala&gt; def createArr[A](seq: A*) = Array[A](seq: _*) &lt;console&gt;:22: error: No ClassTag available for A def createArr[A](seq: A*) = Array[A](seq: _*) ^ scala&gt; def createArr[A : ClassTag](seq: A*) = Array[A](seq: _*) createArr: [A](seq: A*)(implicit evidence$1: scala.reflect.ClassTag[A])Array[A] scala&gt; createArr(1,2,3) res78: Array[Int] = Array(1, 2, 3) scala&gt; createArr("a","b","c") res79: Array[String] = Array(a, b, c) </code></pre> <p><code>ClassTag</code> provides only the information needed to create types at runtime (which are type erased):</p> <pre><code>scala&gt; classTag[Int] res99: scala.reflect.ClassTag[Int] = ClassTag[int] scala&gt; classTag[Int].runtimeClass res100: Class[_] = int scala&gt; classTag[Int].newArray(3) res101: Array[Int] = Array(0, 0, 0) scala&gt; classTag[List[Int]] res104: scala.reflect.ClassTag[List[Int]] =↩ ClassTag[class scala.collection.immutable.List] </code></pre> <p>As one can see above, they don't care about type erasure, therefore if one wants "full" types <code>TypeTag</code> should be used:</p> <pre><code>scala&gt; typeTag[List[Int]] res105: reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[scala.List[Int]] scala&gt; typeTag[List[Int]].tpe res107: reflect.runtime.universe.Type = scala.List[Int] scala&gt; typeOf[List[Int]] res108: reflect.runtime.universe.Type = scala.List[Int] scala&gt; res107 =:= res108 res109: Boolean = true </code></pre> <p>As one can see, method <code>tpe</code> of <code>TypeTag</code> results in a full <code>Type</code>, which is the same we get when <code>typeOf</code> is called. Of course, it is possible to use both, <code>ClassTag</code> and <code>TypeTag</code>:</p> <pre><code>scala&gt; def m[A : ClassTag : TypeTag] = (classTag[A], typeTag[A]) m: [A](implicit evidence$1: scala.reflect.ClassTag[A],↩ implicit evidence$2: reflect.runtime.universe.TypeTag[A])↩ (scala.reflect.ClassTag[A], reflect.runtime.universe.TypeTag[A]) scala&gt; m[List[Int]] res36: (scala.reflect.ClassTag[List[Int]],↩ reflect.runtime.universe.TypeTag[List[Int]]) =↩ (scala.collection.immutable.List,TypeTag[scala.List[Int]]) </code></pre> <p>The remaining question now is what is the sense of <code>WeakTypeTag</code> ? In short, <code>TypeTag</code> represents a concrete type (this means it only allows fully instantiated types) whereas <code>WeakTypeTag</code> just allows any type. Most of the time one does not care which is what (which means <code>TypeTag</code> should be used), but for example, when macros are used which should work with generic types they are needed:</p> <pre><code>object Macro { import language.experimental.macros import scala.reflect.macros.Context def anymacro[A](expr: A): String = macro __anymacro[A] def __anymacro[A : c.WeakTypeTag](c: Context)(expr: c.Expr[A]): c.Expr[A] = { // to get a Type for A the c.WeakTypeTag context bound must be added val aType = implicitly[c.WeakTypeTag[A]].tpe ??? } } </code></pre> <p>If one replaces <code>WeakTypeTag</code> with <code>TypeTag</code> an error is thrown:</p> <pre><code>&lt;console&gt;:17: error: macro implementation has wrong shape: required: (c: scala.reflect.macros.Context)(expr: c.Expr[A]): c.Expr[String] found : (c: scala.reflect.macros.Context)(expr: c.Expr[A])(implicit evidence$1: c.TypeTag[A]): c.Expr[A] macro implementations cannot have implicit parameters other than WeakTypeTag evidences def anymacro[A](expr: A): String = macro __anymacro[A] ^ </code></pre> <p>For a more detailed explanation about the differences between <code>TypeTag</code> and <code>WeakTypeTag</code> see this question: <a href="https://stackoverflow.com/questions/12093752/scala-macros-cannot-create-typetag-from-a-type-t-having-unresolved-type-parame">Scala Macros: “cannot create TypeTag from a type T having unresolved type parameters”</a></p> <p>The official documentation site of Scala also contains a <a href="http://docs.scala-lang.org/overviews/reflection/overview.html" rel="noreferrer">guide for Reflection</a>.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COThanks for your answer! Some comments: 1) `==` for types represents structural equality, not reference equality. `=:=` take into account type equivalences (even non-obvious ones such as equivalences of prefixes that come from different mirrors), 2) Both `TypeTag` and `AbsTypeTag` are based on mirrors. The difference is that `TypeTag` only allows fully instantiated types (i.e. without any type parameters or references abstract type members), 3) A detailed explanation is here: http://stackoverflow.com/questions/12093752
      singulars
    2. CO4) Manifests have the problem of not being able to represent a lot of useful types. Essentially they can only express type refs (plain types such as `Int` and generic types such as `List[Int]`), leaving out such Scala types as e.g. refinements, path-dependent types, existentials, annotated types. Also manifests are a bolt on, so they cannot use the vast knowledge that compiler posesses to, say, calculate a linearization of a type, find out whether one type subtypes another, etc.
      singulars
    3. CO5) To the contrast type tags are not "better integrated", they are simply integrated with the new reflection API (unlike manifests which are not integrated with anything). This provides type tags access to certain aspects of the compiler, e.g. to `Types.scala` (7kloc of code that knows how types are supported to work together), `Symbols.scala` (3kloc of code that knows how symbol tables work), etc.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload