I have some Scala code that makes fairly heavy use of generics, and I have gleaned from the docs that using a manifest in the parametrization constraints can help me work around the type erasure issues (e.g. I want to instantiate a new object of the generic type). Only, I’d like to understand more about how this works. It almost feels like some sort of hashmap that’s getting an entry for every invocation site… Can anyone here elaborate?
class Image[T <: Pixel[T] : Manifest](fun() => T, size: Array[Int], data: Array[T]) {
def this(fun: () => T, size: Array[T]) {
this(fun, size, new Array[T](size(0) * size(1));
}
}
This is something that doesn’t seem to be covered in any of the documentation that I found on the site, and on Google I mostly get older posts that have very different syntax, and since 2.8 seems to have a lot of things changed, I’m not sure those are still accurate.
It’s been awhile since I dug through the source code for Scala in a quest to answer the same question… but the short answer, as I recall –
Manifest is a cheat code to allow the COMPILER to get around Type erasure (it isn’t being used at runtime). It causes multiple code paths to be generated at compile time for the possible input types matching the manifest.
The Manifest is resolved implicitly, but if there is any ambiguity at compile time about what the Manifest type is, the compiler WILL stop.
With a copy of a
Manifestyou have a few things available. The main things you typically want is either thejava.lang.Classthat was erased viaerasure:This is a rather wonky example but shows what is going on. I ran that for the output as well FWIW on Scala 2.8.
The
[T ... : Manifest]boundary is new in Scala 2.8… you used to have to grab the manifest implicitly as shown inImplicitManifest. You don’t actually GET a copy of the Manifest. But you can fetch one inside your code by sayingval m = manifest[T]…manifest[_]is defined onPredefand demonstrably will find the proper manifest type inside a boundaried block.The other two major items you get from a
Manifestis<:<and>:>which test subtype/supertype of one manifest versus another. If I recall correctly these are VERY naive implementation wise and don’t always match but I have a bunch of production code using them to test against a few possible erased inputs. A simple example of checking against another manifest:Jorge Ortiz has a great blog post (albeit old) on this: http://www.scala-blogs.org/2008/10/manifests-reified-types.html
EDIT:
You can actually see what Scala is doing by asking it to print out the results of the erasure compiler phase.
Running, on my last example above
scala -Xprint:erasure test.scalaproduces the following result: