1

Let the following setup:

sealed trait Test[@specialized T] {

  implicit protected def tag: ClassTag[T]

  def xs: Array[T]

  def count(condition: T => Boolean): Int = {
    @tailrec
    def innerLoop(index: Int, acc: Int): Int =
      if (index == xs.length) acc
      else {
        val c: Int = if (condition(xs(index))) 1 else 0
        innerLoop(index + 1, acc + c)
      }

    innerLoop(0, 0)
  }

  def freq(elem: T): Int = count(_ == elem)

}

object Test {

  def apply[@specialized T: ClassTag](xs: Array[T]): Test[T] = if(xs.length % 2 == 0) TestA(xs) else TestB(xs)

  final case class TestA[@specialized T: ClassTag](xs: Array[T]) extends Test[T] {
    protected def tag: ClassTag[T] = classTag[T]
  }

  final case class TestB[@specialized T: ClassTag](xs: Array[T]) extends Test[T] {
    protected def tag: ClassTag[T] = classTag[T]
  }
}

In this case, both count and freq methods can be computed in a generic way, though other methods might exist that are specific to TestA or TestB.

When I benchmark the count method, then there's no performance increase and my feeling is, that somewhere specialized annotation is lost. The same happens with freq too. When the count method is defined in the case classes, then it works as expected and boxing-unboxing is avoided. But this approach will introduce a lot of code duplication.

Even when count is abstract and freq is defined in the trait

sealed trait Test[@specialized T] {

  implicit protected def tag: ClassTag[T]

  def xs: Array[T]

  def count(condition: T => Boolean): Int

  def freq(elem: T): Int = count(_ == elem)

}

and count is overridden in the case classes, the freq method won't be specialized either. What am I missing? Is there a way to define some methods already in the trait and get them specialized?

sanyi14ka
  • 809
  • 9
  • 14

0 Answers0