dk14 dk14 - 2 months ago 15
Scala Question

Why @specialized annotation doesn't work for asInstanceOf?

As far as i understand,

@specialized
annotation should generate some unboxed code for every primitive type i mentioned, but this doesn't work:

scala> def aaa[@specialized(Int, Double, Float, Long) T] = (5.0).doubleValue.asInstanceOf[T]
aaa: [T]=> T

scala> aaa[Int]
unrecoverable error (inside interpreter/compiler)


This compiles:

scala> def aaa[@specialized(Int, Double, Float, Long) T](a: T) = (5.0).doubleValue.asInstanceOf[T]
aaa: [T]=> T

scala> aaa[Int](0)
ClassCastException


But it still uses boxed type for asInstanceOf[T]. This obviously works:

scala> (5.0).asInstanceOf[Int]
res28: Int = 5


UPDATE:
Type erasure and answers like that Writing a generic cast function Scala has nothing to do with my problem. Type erasure just preventing compiler from adding
typecast
byte-code operation for generics, but eventually it will be added - see
ClassCastException
(generated by this op) in my REPL

Answer

The method is specialized, but under separate compilation (i.e., different lines), the specialized method isn't invoked.

In the following, b.B.f works, c.B.f is broken.

$ scala -Xprint:typer,cleanup

scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package a { object A { def aaa[@specialized(Int) T] = (5.0).doubleValue.asInstanceOf[T] }}
package b { object B { def f = a.A.aaa[Int] }}

// Exiting paste mode, now interpreting.

[[syntax trees at end of                     typer]] // <pastie>
package <empty> {
  package a {
    object A extends scala.AnyRef {
      def <init>(): a.A.type = {
        A.super.<init>();
        ()
      };
      def aaa[@specialized(scala.Int) T]: T = scala.this.Predef.double2Double(5.0).doubleValue().asInstanceOf[T]
    }
  };
  package b {
    object B extends scala.AnyRef {
      def <init>(): b.B.type = {
        B.super.<init>();
        ()
      };
      def f: Int = a.A.aaa[Int]
    }
  }
}

[[syntax trees at end of                   cleanup]] // <pastie>
package <empty> {
  package a {
    object A extends Object {
      def aaa(): Object = scala.Double.box(scala.this.Predef.double2Double(5.0).doubleValue());
      <specialized> def aaa$mIc$sp(): Int = scala.this.Predef.double2Double(5.0).doubleValue().toInt();
      def <init>(): a.A.type = {
        A.super.<init>();
        ()
      }
    }
  };
  package b {
    object B extends Object {
      def f(): Int = a.A.aaa$mIc$sp();
      def <init>(): b.B.type = {
        B.super.<init>();
        ()
      }
    }
  }
}


scala> :pa -raw
// Entering paste mode (ctrl-D to finish)

package c { object B { def f = a.A.aaa[Int] }}

// Exiting paste mode, now interpreting.

[[syntax trees at end of                     typer]] // <pastie>
package c {
  object B extends scala.AnyRef {
    def <init>(): c.B.type = {
      B.super.<init>();
      ()
    };
    def f: Int = a.A.aaa[Int]
  }
}

[[syntax trees at end of                   cleanup]] // <pastie>
package c {
  object B extends Object {
    def f(): Int = scala.Int.unbox(a.A.aaa());
    def <init>(): c.B.type = {
      B.super.<init>();
      ()
    }
  }
}
Comments