0
votes

I am writing a Scala class that implements a 2-dimensional matrix of arbitrary objects. I need the class to be more specialized than nested pair of IndexedSeq objects, but extending a collections class is overkill, so I'm writing my own. In order to return the correct type from methods in my matrix class, I am using the implicit builder idiom, but at runtime I get a "could not find implicit value for parameter" error which I don't understand.

A stripped-down version of my matrix class looks like this.

trait MatrixBuilder[V, M <: Matrix[V]] {
  def apply(values: IndexedSeq[IndexedSeq[V]]): M
}

abstract class Matrix[V](values: IndexedSeq[IndexedSeq[V]]) extends Function2[Int, Int, V] {

  def apply(row: Int, col: Int): V = values(row)(col)

  def set[M <: Matrix[V]](row: Int, col: Int, value: V)(implicit builder: MatrixBuilder[V, M]): M =
    builder(values.updated(row, values(row).updated(col, value)))
}

case class IntMatrix(values: IndexedSeq[IndexedSeq[Int]]) extends Matrix[Int](values)

object IntMatrix {
  def apply(n: Int) = new IntMatrix(IndexedSeq.fill(n, n)(0))

  implicit object IntMatrixBuilder extends MatrixBuilder[Int, IntMatrix] {
    def apply(values: IndexedSeq[IndexedSeq[Int]]) = IntMatrix(values)
  }
}

I want the set function to set the specified cell then return a new matrix of the correct type. So I expect IntMatrix(2).set(0,0,5) to return an IntMatrix object with zeros in all cells except (0,0), where it should have a 5. Instead I get the following error at runtime.

error: could not find implicit value for parameter builder: MatrixBuilder[Int,M]
    IntMatrix(2).set(0,0,5)

What am I doing wrong here?


As pedrofurla notes below, the code does work in the REPL if you first run the line import IntMatrix._. And looking at the collections documentation, there appear to be similar import statements in source code using builders. I tried adding one to my IntMatrix class.

case class IntMatrix(values: IndexedSeq[IndexedSeq[Int]]) extends Matrix[Int](values) {
    import IntMatrix._
}

But this has no effect. (In fact my IDE IntelliJ flags this as an unused import statement.)

For comparison I copied over the RNA sequence example from the collections documentation linked above verbatim. There the import RNA._ line is not marked as superfluous and all operations return the correct type. If the answer is that I need to add an import IntMatrix._, I can't figure out where to put it.

1
You might want to include a definition of your Solution class, so someone can paste the code somewhere, make the IntMatrix(2).set(0,0,5) call, and reproduce the issue. I'm tempted to think that since IntMatrix isn't parameterized it might not be seen as a subclass of Matrix[Int], and so doesn't fit the definition of your type M required for the implicit builder? I'm not really sure about that though. This was at runtime not compile time?nairbv
Solution was a typo. It should have been IntMatrix. I fixed this. This is a runtime error. IntMatrix extends Matrix[Int] which I think should meet the type signature of the builder.W.P. McNeill
It should be in scope during the call of set. Add this explanation to my answer.pedrofurla

1 Answers

1
votes

This little code worked here:

scala> import IntMatrix._
import IntMatrix._

scala> IntMatrix(2).set(0,0,5)
res1: Mat.IntMatrix = <function2>

Implicit parameters are filled by compiler in the call site, so they have to be available in the scope set is being invoked.