Type specialization on Scala 2.8

How to Try @specialized annotation

The functionality of @specialized annotation has not been available in Scala 2.8 trunk yet(28 May 2009),
and it seems the source code has been only existed in the branch specialized. Here are steps to retrieve
the code, build them,etc.

  • $ svn co http://lampsvn.epfl.ch/svn-repos/scala/scala/branches/specialized specialized
  • $ cd specialized
  • $ export ANT_OPTS="-Xms512M -Xmx512M"
  • $ ant build
  • $ ./build/pack/bin/scalac -Yspecialize foo.scala #, where foo.scala uses @specialized annotation

Documentations

It seems there have not existed documentations, which describe what is it and how to use it, in detail. The current source of informations is the following paper and its source code,

Problems in Handling Primitive Values in Generics

For example, every primitive values must be boxed in the parameterized Array,
  • $ cat > example1.Scala
    class Example1 {
      def reverse[T](a:Array[T]){
        for(i <- 0 until a.length)
          a(i) = a(a.length - i - 1)
      }
      reverse(Array(1,2,3))
    }
  • $ scalac -Xprint:erasure example1.Scala
    ...
    Example1.this.reverse(new Scala.runtime.BoxedIntArray(Scala.Array.apply(new Scala.runtime.BoxedIntArray(Array[Int]{1, 2, 3}))))
    ...

specialization

For example, every primitive values must be boxed in the parmetelized Array,
  • $ cat > example2.Scala
    trait MyFunction1[@specialized -T, @specialized +R]{
      def apply(x:T):R
    }
    class Example2{
      def map[@specialized A](xs:Array[A], f:MyFunction1[A,A]):Unit = {
        for(i <- 0 until xs.length)
          xs(i) = f.apply(xs(i))
      }
      class anonfun extends MyFunction1[Int, Int]{
        def apply(x:Int):Int = x*x
      }
      map(Array(1,2,3), new anonfun)
    }
  • $ scalac -Xprint:erasure example2.Scala
    ...
      def apply(x: Int): Int = x.*(x);
      <bridge> def apply(y$1: java.lang.Object): java.lang.Object = Scala.Int.box(anonfun.this.apply(Scala.Int.unbox(y$1)))
    ...
  • $ scalac -Xprint:erasure -Yspecialize example2.Scala
    ...
      apply(x: Int): Int = anonfun.this.apply$mcII$sp(x);   # anonfun
      apply$mcII$sp(y$1: Int): Int = y$1.*(y$1);   # anonfun
    ...
      final def apply(i: Int): Unit = y$1.update(i, y$2.apply$mcII$sp(y$1.apply(i))); # map$mIc$sp
    ...
      Example2.this.map$mIc$sp(Scala.Array.apply(Scala.runtime.ScalaRunTime.boxArray(Array[Int]{1, 2, 3})), new Example2#anonfun(Example2.this));
    ...


Evaluation

  • increase of code size: stdlib 17%, specific 300%
  • speedup(Nx):  steady state: fun 22.88, arrays 40.3

Future Work

  • The current compilation scheme has a limitation when a superclass of a generic class is instantiated.
  • parameterizing the annotation at the specific types that need specilization; @specialization("Int")
  • Having specialized instances for primitive types could be used for giving more precise Type at runtime.
  • user-defined specializations
Comments