Scala - How to Convert Generic List To Array and avoid "No ClassTag available for T"

883 Views Asked by At

I am working on what should be a trivial piece of code. I want to take a List, and convert it to an equivalent Array:

import scala.collection.JavaConverters

object Help extends App {
  def f1[T](lst: List[T]) = {
    lst.toArray
  }

  val x = List(1, 2, 3)
  println(f1(x))
}

Running this code gives:

"No ClassTag available for T"

How can I avoid this problem; I am coming from a Python background so would appreciate a response that gives me an understanding of the mechanics here.

Thank you!

1

There are 1 best solutions below

2
On BEST ANSWER

Try adding implicit ClassTag parameter like so

import scala.reflect.ClassTag

def f1[T](lst: List[T])(implicit ev: ClassTag[T]) = {
  lst.toArray
}

The reason is clear if we have a look at signature of toArray

def toArray[B >: A: ClassTag]: Array[B]

which is equivalent to

def toArray[B >: A](implicit ev: ClassTag[B]): Array[B]

so you have to thread the implicit parameter from f1 down to toArray.

would appreciate a response that gives me an understanding of the mechanics here

The key is to understand Array is not a true Scala collection. For once, it is not a subtype of Iterable

implicitly[Array[Int] <:< Iterable[Int]] // error

Another difference between Array and true Scala collections is the absence of need for ClassTag for true Scala collections. The reason for this is Scala collections go through a process of type erasure which means runtime knows it is a List but does not differentiate between List[Int] and List[String], for example. However this does not hold for Array. At runtime there is indeed a difference between Array[Int] and Array[String]. Hence ClassTag is a mechanism invented to carry type information, which exists only at compile-time, over to runtime, so Array can have the behaviour as in Java.

You will encounter other differences, for example

Array(42) == Array(42)  // false
List(42) == List(42)    // true

Best practice is to avoid Array if possible.