Monday, April 16, 2012

Is it possible for Scala to have reified generics without changing the JVM?


I've recently started learning Scala and was disappointed (but not surprised) that their generics are also implemented via type erasure.



My question is, is it possible for Scala to have reified generics, or would the JVM need to be changed in some way? If the JVM does need to be changed, what exactly would need to be changed?


Source: Tips4all

4 comments:

  1. No - it is not possible for Scala to run as Java-equivalent bytecode if that bytecode does not support reified generics.

    When you ask "what is it that needs to be changed?", the answer is: the bytecode specification. Currently the bytecode does not allow for the parametrized type of a variable to be defined. It has been decided that as a modification to the bytecode to support reified generics would break backwards compatibility, that generics would have to be implemented via type erasure.

    In order to get around this, Scala has used the power of its implicit mechanism to define a Manifest which can be imported in any scope to discover type information at runtime. Manifests are experimental and largely undocumented but they are coming as part of the library in 2.8. Here is another good resource on Scala reified generics / Manifests

    ReplyDelete
  2. Just to complement oxbow_lakes, there's a question on Stack Overflow about how to get around type erasure in Scala.

    ReplyDelete
  3. "implicit Manifest" is a Scala compiler trick and it does not make generics in Scala reified. The Scala compiler, when it sees a function with "implicit m: Manifest[A]" parameter and it knows the generic type of A at the call site, it will wrap the class of A and its generic type parameters into a Manifest and make it available inside the function. However, if it could not figure out the true type of A, then it has no way of creating a Manifest. In other words, Manifest has to be passed along the function calling chain if the inner function needs it.

    scala> def typeName[A](a: A)(implicit m: reflect.Manifest[A]) = m.toString
    typeName: [A](a: A)(implicit m: scala.reflect.Manifest[A])java.lang.String

    scala> typeName(List(1))
    res6: java.lang.String = scala.collection.immutable.List[int]

    scala> def foo[A](a: A) = typeName(a)
    <console>:5: error: could not find implicit value for parameter m:scala.reflect.Manifest[A].
    def foo[A](a: A) = typeName(a)
    ^

    scala> def foo[A](a: A)(implicit m: reflect.Manifest[A]) = typeName(a)
    foo: [A](a: A)(implicit m: scala.reflect.Manifest[A])java.lang.String

    scala> foo(Set("hello"))
    res8: java.lang.String = scala.collection.immutable.Set[java.lang.String]

    ReplyDelete
  4. Once scalac is a compiler and potentially has ability to embellish the generated code with whatever data structures, tricks and whatever is necessary to perform a certain task, I do not understand why scalac does not mimic what C++ templates do.

    What I mean is that scalac would have the ability to see...

    // definition
    class Klass[T] {
    value : T
    }

    //calls
    floats = Klass[float]
    doubles = Klass[double]


    ... and "expand" to something like this:

    // definition
    class Klass_float {
    value : float
    }
    class Klass_double {
    value : double
    }

    // calls
    floats = Klass_float
    doubles = Klass_double


    Does it make sense?

    Just a side note:
    It is possible to circumvent type erasure employing anonymous classes.
    See: Using TypeTokens to retrieve generic parameters

    Thanks

    ReplyDelete