19
votes

It seems I don't understand something important, maybe about erasure (damn it).

I have a method, which I wanted to create array of size n filled with values from gen:

def testArray[T](n: Int, gen: =>T) {
  val arr = Array.fill(n)(gen)
  ...
}

And use it, for example as:

testArray(10, util.Random.nextInt(10))

But I get error:

scala: could not find implicit value for evidence parameter of type scala.reflect.ClassManifest[T]
val arr = Array.fill(n)(gen)
                       ^

Please, explain what I did wrong, why this error, and what kind of code it makes impossible?

2

2 Answers

14
votes

That is because in testArray the concrete type of T is not known at compile time. Your signature has to look like def testArray[T : ClassManifest](n: Int, gen: =>T), this will add an implicit parameter of type ClassManifest[T] to your method, that is automatically passed to the call of testArray and then further passed to the Array.fill call. This is called a context bound.

5
votes

The Array.fill method has the following signature:

def fill[T](n: Int)(elem: => T)(implicit arg0: ClassManifest[T]): Array[T]

In order to get an instance of ClassManifest[T] you need to know the concrete type. A ClassManifest can be obtained like this:

implicitly[ClassManifest[String]]

A ClassManifest is implicitly available for every concrete type.

For any implicit error, you can add the implicits you require to the method with the type parameter:

def wrap[T](n:Int)(elem: => T)(implicit c:ClassManifest[T], o:Ordering[T])

If you did not yourself introduce ClassManifest or Ordering, the writers of the library have (most likely) provided sensible defaults for you.

If you would call the wrap method:

wrap(2)(3)

It's expanded like this:

wrap[Int](2)(3)(implicitly[ClassManifest[Int]], implicitly[Ordering[Int]])

If you introduced a custom class Person here, you would get an error for not finding an implicit instance of Ordering[Person]. The writers of the library could not have known how to order Person. You could solve that like this:

class Person

implicit val o = new Ordering[Person] { // implement required methods }

wrap(2)(new Person)

The Scala compiler looks in different scopes for implicits, an Ordering would usually not be specified like this. I suggest you look up implicit resolution on the internet to learn more about it.