A Manifest[T] is an opaque descriptor for type T. Its supported use is to give access to the erasure of the type as a Class instance, as is necessary for the creation of native Arrays if the class is not known at compile time.
A ClassTag[T] stores the erased class of a given type T , accessible via the runtimeClass field. This is particularly useful for instantiating Array s whose element types are unknown at compile time. ClassTag s are a weaker special case of scala. reflect. api.
The compiler knows more information about types than the JVM runtime can easily represent. A Manifest is a way for the compiler to send an inter-dimensional message to the code at runtime about the type information that was lost.
This is similar to how the Kleptonians have left encoded messages in fossil records and the "junk" DNA of humans. Due to limitations of lightspeed and gravitational resonance fields, they are unable to communicate directly. But, if you know how to tune into their signal, you can benefit in ways you cannot imagine, from deciding what to eat for lunch or which lotto number to play.
It isn't clear if a Manifest would benefit the errors you are seeing without knowing more detail.
One common use of Manifests is to have your code behave differently based on the static type of a collection. For example, what if you wanted to treat a List[String] differently from other types of a List:
def foo[T](x: List[T])(implicit m: Manifest[T]) = {
if (m <:< manifest[String])
println("Hey, this list is full of strings")
else
println("Non-stringy list")
}
foo(List("one", "two")) // Hey, this list is full of strings
foo(List(1, 2)) // Non-stringy list
foo(List("one", 2)) // Non-stringy list
A reflection-based solution to this would probably involve inspecting each element of the list.
A context bound seems most suited to using type-classes in scala, and is well explained here by Debasish Ghosh: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html
Context bounds can also just make the method signatures more readable. For example, the above function could be re-written using context bounds like so:
def foo[T: Manifest](x: List[T]) = {
if (manifest[T] <:< manifest[String])
println("Hey, this list is full of strings")
else
println("Non-stringy list")
}
A Manifest was intended to reify generic types that get type-erased to run on the JVM (which does not support generics). However, they had some serious issues: they were too simplistic, and were unable to fully support Scala's type system. They were thus deprecated in Scala 2.10, and are replaced with TypeTag
s (which are essentially what the Scala compiler itself uses to represent types, and therefore fully support Scala types). For more details on the difference, see:
when do you need it?
Before 2013-01-04, when Scala 2.10 was released.
Not a complete answer, but regarding the difference between Manifest
and ClassManifest
, you can find an example in the Scala 2.8 Array
paper:
The only remaining question is how to implement generic array creation. Unlike Java, Scala allows an instance creation new
Array[T]
whereT
is a type parameter. How can this be implemented, given the fact that there does not exist a uniform array representation in Java?The only way to do this is to require additional runtime information which describes the type
T
. Scala 2.8 has a new mechanism for this, which is called a Manifest. An object of typeManifest[T]
provides complete information about the typeT
.Manifest
values are typically passed in implicit parameters; and the compiler knows how to construct them for statically known typesT
.There exists also a weaker form named
ClassManifest
which can be constructed from knowing just the top-level class of a type, without necessarily knowing all its argument types.
It is this type of runtime information that’s required for array creation.
Example:
One needs to provide this information by passing a
ClassManifest[T]
into the method as an implicit parameter:
def tabulate[T](len:Int, f:Int=>T)(implicit m:ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
As a shorthand form, a context bound1 can be used on the type parameter
T
instead,
(See this SO question for illustration)
, giving:
def tabulate[T: ClassManifest](len:Int, f:Int=>T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
When calling tabulate on a type such as
Int
, orString
, orList[T]
, the Scala compiler can create a class manifest to pass as implicit argument to tabulate.
Let's also chck out manifest
in scala
sources (Manifest.scala
), we see:
Manifest.scala:
def manifest[T](implicit m: Manifest[T]) = m
So with regards to following example code:
def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
if (m <:< manifest[String]) {
"its a string"
} else {
"its not a string"
}
}
we can see that the manifest
function
searches for an implicit m: Manifest[T]
which satisfies the type parameter
you provide in our example code it was manifest[String]
. So when you call something like:
if (m <:< manifest[String]) {
you are checking if the current implicit m
which you defined in your function is of type manifest[String]
and as the manifest
is a function of type manifest[T]
it would search for a specific manifest[String]
and it would find if there is such an implicit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With