In using a framework like FastUtils with Scala, how do you generate the appropriate code based on the effective specialization as the framework itself has specialised data structures? I.e., how you you programmatically figure out what is being specialized and execute the appropriate code? So how do you deal with path related typing in such cases.
For objects
class Container[@specialized T](var window: Int) {
val data = new ObjectArrayList[T](window)
}
For char
I want it to be:
class Container[@specialized T](var window: Int) {
val data = new CharArrayList(window)
}
But this should be based on the specialization of T
. If I am to put this differently the sudo code would be perhaps like
class Container[@specialized T](var window: Int) {
val data = specialisationOf(T) match {
case "Char" => new CharArrayList(window)
case "Int" => new IntegerArrayList(window)
...
...
...
case _ => new ObjectArrayList[T](window)
}
}
As already explained in this question, you can encapsulate the specialized implementation in a typeclass. This would look more or less like the following code.
import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.chars.CharArrayList
import it.unimi.dsi.fastutil.objects.ObjectArrayList
class Container[@specialized(Int,Char) T](window: Int)(implicit impl: ContainerImpl[T]) {
impl.init(window)
def add(element: T) = impl.add(element)
override def toString = impl.toString
}
trait ContainerImpl[@specialized(Int,Char) T] {
def init(window: Int): Unit
def add(element: T): Unit
def toString: String
}
object ContainerImpl extends LowerPriorityImplicits {
implicit def intContainer = new ContainerImplInt
implicit def charContainer = new ContainerImplChar
}
trait LowerPriorityImplicits {
implicit def anyContainer[T] = new ContainerImplT[T]
}
final class ContainerImplInt extends ContainerImpl[Int] {
var data: IntArrayList = _
def init(window: Int) = data = new IntArrayList(window)
def add(element: Int) = data.add(element)
override def toString = data.toString
}
final class ContainerImplChar extends ContainerImpl[Char] {
var data: CharArrayList = _
def init(window: Int) = data = new CharArrayList(window)
def add(element: Char) = data.add(element)
override def toString = data.toString
}
final class ContainerImplT[T] extends ContainerImpl[T] {
var data: ObjectArrayList[T] = _
def init(window: Int) = data = new ObjectArrayList(window)
def add(element: T) = data.add(element)
override def toString = data.toString
}
Do note that although the implementation of add
always looks the same, the method being called on data
is a different overload every time. If you would write this in a more polymorphic way, the most specific add
method would not be chosen, and your Int
or Char
will need to be boxed.