This doc page is specific to features shipped in Scala 2, which have either been removed in Scala 3 or replaced by an alternative. Unless otherwise stated, all the code examples in this page assume you are using Scala 2.
As with other JVM languages, Scala’s types are erased at run time. This means that if you were to inspect the runtime type of some instance, you might not have access to all type information that the Scala compiler has available at compile time.
Like scala.reflect.Manifest
, TypeTags
can be thought of as objects which
carry along all type information available at compile time, to runtime. For
example, TypeTag[T]
encapsulates the runtime type representation of some
compile-time type T
. Note however, that TypeTag
s should be considered to
be a richer replacement of the pre-2.10 notion of a Manifest
, that are
additionally fully integrated with Scala reflection.
There exist three different types of TypeTags:
-
scala.reflect.api.TypeTags#TypeTag
. A full type descriptor of a Scala type. For example, aTypeTag[List[String]]
contains all type information, in this case, of typescala.List[String]
. -
scala.reflect.ClassTag
. A partial type descriptor of a Scala type. For example, aClassTag[List[String]]
contains only the erased class type information, in this case, of typescala.collection.immutable.List
.ClassTag
s provide access only to the runtime class of a type. Analogous toscala.reflect.ClassManifest
. -
scala.reflect.api.TypeTags#WeakTypeTag
. A type descriptor for abstract types (see corresponding subsection below).
Obtaining a TypeTag
Like Manifest
s, TypeTag
s are always generated by the compiler, and can be obtained in three ways.
via the Methods typeTag
, classTag
, or weakTypeTag
One can directly obtain a TypeTag
for a specific type by simply using
method typeTag
, available through Universe
.
For example, to obtain a TypeTag
which represents Int
, we can do:
import scala.reflect.runtime.universe._
val tt = typeTag[Int]
Or likewise, to obtain a ClassTag
which represents String
, we can do:
import scala.reflect._
val ct = classTag[String]
Each of these methods constructs a TypeTag[T]
or ClassTag[T]
for the given
type argument T
.
Using an Implicit Parameter of Type TypeTag[T]
, ClassTag[T]
, or WeakTypeTag[T]
As with Manifest
s, one can in effect request that the compiler generate a
TypeTag
. This is done by simply specifying an implicit evidence parameter
of type TypeTag[T]
. If the compiler fails to find a matching implicit value
during implicit search, it will automatically generate a TypeTag[T]
.
Note: this is typically achieved by using an implicit parameter on methods and classes only.
For example, we can write a method which takes some arbitrary object, and
using a TypeTag
, prints information about that object’s type arguments:
import scala.reflect.runtime.universe._
def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
val targs = tag.tpe match { case TypeRef(_, _, args) => args }
println(s"type of $x has type arguments $targs")
}
Here, we write a generic method paramInfo
parameterized on T
, and we
supply an implicit parameter (implicit tag: TypeTag[T])
. We can then
directly access the type (of type Type
) that tag
represents using method
tpe
of TypeTag
.
We can then use our method paramInfo
as follows:
scala> paramInfo(42)
type of 42 has type arguments List()
scala> paramInfo(List(1, 2))
type of List(1, 2) has type arguments List(Int)
Using a Context bound of a Type Parameter
A less verbose way to achieve exactly the same as above is by using a context
bound on a type parameter. Instead of providing a separate implicit parameter,
one can simply include the TypeTag
in the type parameter list as follows:
def myMethod[T: TypeTag] = ...
Given context bound [T: TypeTag]
, the compiler will simply generate an
implicit parameter of type TypeTag[T]
and will rewrite the method to look
like the example with the implicit parameter in the previous section.
The above example rewritten to use context bounds is as follows:
import scala.reflect.runtime.universe._
def paramInfo[T: TypeTag](x: T): Unit = {
val targs = typeOf[T] match { case TypeRef(_, _, args) => args }
println(s"type of $x has type arguments $targs")
}
scala> paramInfo(42)
type of 42 has type arguments List()
scala> paramInfo(List(1, 2))
type of List(1, 2) has type arguments List(Int)
WeakTypeTags
WeakTypeTag[T]
generalizes TypeTag[T]
. Unlike a regular TypeTag
,
components of its type representation can be references to type parameters or
abstract types. However, WeakTypeTag[T]
tries to be as concrete as possible,
i.e., if type tags are available for the referenced type arguments or abstract
types, they are used to embed the concrete types into the WeakTypeTag[T]
.
Continuing the example above:
def weakParamInfo[T](x: T)(implicit tag: WeakTypeTag[T]): Unit = {
val targs = tag.tpe match { case TypeRef(_, _, args) => args }
println(s"type of $x has type arguments $targs")
}
scala> def foo[T] = weakParamInfo(List[T]())
foo: [T]=> Unit
scala> foo[Int]
type of List() has type arguments List(T)
TypeTags and Manifests
TypeTag
s correspond loosely to the pre-2.10 notion of
scala.reflect.Manifest
s. While scala.reflect.ClassTag
corresponds to
scala.reflect.ClassManifest
and scala.reflect.api.TypeTags#TypeTag
mostly
corresponds to scala.reflect.Manifest
, other pre-2.10 Manifest types do not
have a direct correspondence with a 2.10 “Tag
” type.
-
scala.reflect.OptManifest is not supported. This is because
Tag
s can reify arbitrary types, so they are always available. -
There is no equivalent for scala.reflect.AnyValManifest. Instead, one can compare their
Tag
with one of the baseTag
s (defined in the corresponding companion objects) in order to find out whether or not it represents a primitive value class. Additionally, it’s possible to simply use<tag>.tpe.typeSymbol.isPrimitiveValueClass
. -
There are no replacement for factory methods defined in the Manifest companion objects. Instead, one could generate corresponding types using the reflection APIs provided by Java (for classes) and Scala (for types).
-
Certain manifest operations(i.e.,
<:<
,>:>
andtypeArguments
) are not supported. Instead, one could use the reflection APIs provided by Java (for classes) and Scala (for types).
In Scala 2.10, scala.reflect.ClassManifest
are deprecated, and it is
planned to deprecate scala.reflect.Manifest
in favor of TypeTag
s and
ClassTag
s in an upcoming point release. Thus, it is advisable to migrate any
Manifest
-based APIs to use Tag
s.