When I have a @specialized class, I retain the information about what primitive my type is. Is there a fast way to get a ClassTag[T]
, e.g. to create arrays?
This does not compile, because no ClassTag[T] is available
class Foo[@specialized T] {
def bar: Array[T] = new Array[T]
}
This works, but I want to avoid passing the ClassTag
class Foo[@specialized T: ClassTag] {
def bar: Array[T] = new Array[T]
}
This works, but is slow:
class Foo[@specialized T] {
def bar: Array[T] = new Array[T]
implicit def classTag: ClassTag[T] = {
val name = getClass.getName
if(name.endsWith("$I$sp") ClassTag.Int
else if(name.endsWith("$L$sp") ClassTag.Long
else ??? // you get the idea
}
}
Specialization happens later than materialization of ClassTags at typer, so there's the matter of the barn door.
The other issue is that specialization will create double definitions, so it's not trivial to hand-specialize a method in the obvious way.
Here's an attempt to mix-in the specialized method that provides a class tag.
Specialized f
calls specialized ct
which is overridden in the trait.
I don't know that the dummy arg to ct
is necessary to make it specialize; maybe the ClassTag[A]
result type isn't enough.
$ scalam
Welcome to Scala 2.12.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions for evaluation. Or try :help.
scala> import reflect.ClassTag
import reflect.ClassTag
scala> class CT[@specialized(Int) A] {
| def ct(a: A): ClassTag[A] = ???
| def f: Array[A] = ct(null.asInstanceOf[A]).newArray(1)
| }
defined class CT
scala> trait CTS { def ct$mcI$sp(i: Int): ClassTag[Int] = reflect.classTag[Int] }
defined trait CTS
scala> (new CT[Int] with CTS).f
res0: Array[Int] = Array(0)
Showing specialized invocation:
scala> :javap -c -
Compiled from "<console>"
[snip]
16: invokevirtual #32 // Method $line16/$read$$iw$$iw$$anon$1.f$mcI$sp:()[I
19: putfield #24 // Field res0:[I