Producing a matrix class that supports any size

I'm doing exercise 11.8 from Scala for impatient, asking to write a matrix class:

Provide a class Matrix - you can choose whether you want to implement 2 x 2 matrices, square matrices of any size, or m x n matrices. Supply operations + and *. The latter should also work with scalars, for example mat * 2. A single element should be accessible as mat(row, col).

The code is working, but may be there can be improvements to make code more functional or more stable:

class Matrix(val n: Int, val m: Int, fun: (Int, Int) => Double) {
private val matrix = Array.tabulate[Double](n,m)(fun)

def +(another: Matrix) = {
if (n != another.n || m != another.m)
throw new IllegalArgumentException("Sizes of arrays don't match.")
else
new Matrix(n, m, (i, j) => this(i)(j) + another(i)(j))
}
def *(another: Matrix) = {
if (m != another.n)
throw new IllegalArgumentException("Sizes of arrays don't match.")
else
new Matrix(n, another.m, (i,j) => { var sum = 0.0;
for (k <- matrix(i).indices) sum += matrix(i)(k) * another(k)(j);
sum }
)
}
def *(k: Int) = new Matrix(n, m, k * matrix(_)(_) )

def apply(i: Int)(j: Int) = matrix(i)(j)

override def toString = {
var result = ""
for (row <- matrix) {
for (value <- row)
result += value + "  "

result += "\n"
}
result
}
}
• It's curious how you use a function as part of the constructor parameters. Is that proposed by the book? If so, could you give more details? If not, then I think you went the wrong way. No clue why the tabulate is in there either, and I'm not sure if it's something the book said that you didn't mention, or something you came up with for reasons I don't understand. – Daniel C. Sobral Aug 10 '12 at 18:11
• Hi, thanks for response. I updated the question. No, it was not part of task, I used it by myself. What's wrong with function in constructor and tabulate, could you please explain? May be Array in constructor would be better, I just decided that it's quicker to generate values with function, than create 2-dimensional array. – damluar Aug 10 '12 at 19:54
• There should be a way to update individual values in the matrix, I think. The use of the function is clever, but won't work if you are allowed to update (create a new matrix with updated) individual values. I suggest you redo the problem with that additional (implicit?) requisite. – Daniel C. Sobral Aug 10 '12 at 20:32

Remove all var. Doesn't the book show for...yield by that point? For example:

(i,j) => {
var sum = 0.0;
for (k <- matrix(i).indices) sum += matrix(i)(k) * another(k)(j);
sum
}

Can be replaced with:

(i,j) => (for (k <- matrix(i).indices) yield matrix(i)(k) * another(k)(j)).sum

The var on toString can be replaced by using mkString. I'll let you work out for yourself how to do that, now that I called your attention to that method. And, yes, it that method works on Array as well, though it doesn't appear on Scaladoc for Scala up to 2.9.2 because it is added implicitly. I suggest you use the nightly scaladoc to look things up -- the documentation there is better, though it may show things not available on release versions, and so is the tool itself.