Problems with manifests/typetags when updating to Scala 2.10
manifest, scala, scala-2.10
Solution
Yes, you mostly have the equivalence `TypeTag <-> Manifest` and `ClassTag <-> ClassManifest`. Except that there are some things that used to be handled by Manifests that have no direct equivalent because those operations were moved deeper into the reflection API instead, like the factory methods on the `Manifest` object.
`ClassTag` is now basically only used to get the runtime (erased) class of something. The main thing it is used for is array creation, but you can use it for other purposes without problem. So yes, `classTag[T].runtimeClass` is the new `manifest[T].erasure` and is completely equivalent to it.
This is the place that has changed the most. 2.10 introduced the new reflection API, and you are supposed to use it when you want to answer specific questions about types (like "does `A <:< B`?"). And the entry point into the reflection API for a type is... its `TypeTag`.
Assuming type tags for `A` and `T` are in scope, the new `manifest[T] <:< manifest[A]` would indeed be `typeOf[T] <:< typeOf[A]`. The method `<:<` is not deprecated here, see the scaladoc. There is however a deprecated `<:<` in `ClassTag` because `ClassManifest` used to have one, and `ClassTag` is the new `ClassManifest`.
See the section about Common Operations on Types of the reflection guide, and the SO question What is a TypeTag and how do I use it.
I do not think there is a direct way to go from a `TypeTag` to a `ClassTag`. Think of it this way:
if you need sub-typing or type equality checking, you cannot use a `ClassTag`, you need a `TypeTag`;
if you also need the name of that type, you can just get it from the `TypeTag`: `typeOf[T].typeSymbol.name.decoded`. This would give you the erased name, just like the class name you used to get (`List` for `List[Int]`, or `Map` for `Map[String, Int]`). This is slightly different from getting the name of the actual `Class` though. If you need the fulll un-erased name (`List[Int]`), `typeOf[T].normalize.toString` is enough.
if you also absolutely need a `Class` instance, or a real class name that you can pass around and load later on with reflection, I think you have no choice but ask for a `ClassTag` too..
Edit: I just found this SO question, so yes, it is possible to get a `ClassTag` from a `TypeTag`. It is just sad there is no helper method somewhere in the reflection library for this.
Edit 2: as requested, here is how to convert from `TypeTag` to `ClassTag`:
import reflect.runtime.universe._
import reflect.ClassTag
def classTag2[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
// example:
def doSomething[T : TypeTag] = {
val c = classTag2[T]
c.runtimeClass.getName
}
Problem
I'm sitting in front of a project about 10000 LoC. I have to update this Project from Scala 2.9 to 2.10. This was well done, but I got many deprecation warnings because of the manifests. After using the search function of stackoverflow and many other sites, I have not so many questions. I want to summarize; the key points are: TypeTags and ClassTags are much better than Manifests and ClassManifest. Especially you can use these as synonyms (TypeTags <-> Manifests and ClassTags <-> ClassManifest) TypeTags are more powerfull than ClassTags, respectively ClassTags are more restricted TypeTags. My first question: In this project, the method `manifest[T].erasure.getSimpleName` is often used. Now I can't only switch this to `typeTag[T].runtimeClass.getSimpleName` because the code wouldn't compile, but with `classTag[T].runtimeClass.getSimpleName` it would compile. Would this influence the semantics? (Note: The method `erasure` is also deprecated; you have to use `runtimeClass` instead) The second question: Type checking of manifests in Scala 2.9 was kind of: `manifest[T] <:< manifest[A]`. In Scala 2.10, I would write this `typeOf[T] <:< typeOf[A]`. But `<:<` is deprecated?! Am I able to cast a TypeTag to a ClassTag? I.e.: If I only use manifests for type checking (Nr. 3) and name extracting (Nr. 2): Am I able to rename every Manifest/ClassManifest to ClassTag?