1

I've read up a little on Manifests and the erasure-avoidance techniques required to allow Scala to do things like "new Array[Array[T]]", but I'm a little stumped with this one....

I've got a method that sort of tabulates up a bunch of rows in an array like a spreadsheet. For example imagine a 2D array like this:

11,   5,    4
8,    3,    7
2,    1,    4

I wrote a method that sums up the columns of that array and spits out a 1D array like [21, 9, 15]

I want to genericize it beyond just Ints (like Doubles or Floats maybe), and when I add a parameter and manifest I get a compile error.

Here's the code

def sumGrid[T](grid: Array[Array[T]])(implicit m: ClassManifest[T]): Array[T] = {

  val sum = new Array[T](grid(0).size)

  for(i <- 0 until grid.size) {
    for(j <- 0 until grid(0).size) {
      sum(j) = sum(j) + grid(i)(j)
    }
  }  
  sum
}

Here's the compile error:

[ERROR] ...scala/euler/GridOperations.scala:126: error: type mismatch;
[INFO]  found   : T
[INFO]  required: String
[INFO]         sum(j) = sum(j) + grid(i)(j)
[INFO]                                  ^
[ERROR] one error found

What's going on here? Why is String "required"?

1
  • 3
    Note that in this case you can sidestep the issue by writing def sumGrid[T: Numeric](grid: Array[Array[T]]) = grid.transpose.map(_.sum). Commented Jun 20, 2012 at 22:22

2 Answers 2

6

Because you use the + operator which is always defined for strings. Any type can be converted to String (toString is always defined) and thus it will work for any type T.

But you could add some constraints on T to ensure it corresponds to the arithmetic operation. For instance, you can use implicits to get a Numeric objects defining the addition for type T:

def sumGrid[T](grid: Array[Array[T]])
(implicit m: ClassManifest[T], num: Numeric[T]): Array[T] = {

  val sum = new Array[T](grid(0).size)

  for(i <- 0 until grid.size) {
    for(j <- 0 until grid(0).size) {
      sum(j) = num.plus( sum(j), grid(i)(j) )
    }
  }  
  sum
}
Sign up to request clarification or add additional context in comments.

Comments

0

You handled the Array part, but T doesn't have any constrains that say it has a + method. Because of that, Scala thinks you are adding strings -- it will auto-convert any type to a String when you add it to another String. So it auto-converted sum(j) to String, and now expects grid(i)(j) to be another String, at which point it gives up and fails.

You can handle the thing about T being numeric in a similar manner to the ClassManifest stuff. Here:

// I'm using the "context bound" notation, to make the declaration shorter and
// more obvious on what I'm saying about T
def sumGrid[T : ClassManifest : Numeric](grid: Array[Array[T]]): Array[T] = {
  // the following line, plus the Numeric bound, makes T usable as a number
  import scala.math.Numeric.Implicits._

  val sum = new Array[T](grid(0).size)

  for(i <- 0 until grid.size) {
    for(j <- 0 until grid(0).size) {
      sum(j) = sum(j) + grid(i)(j)
    }
  }  
  sum
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.