开发者

Scala confused about mutability and Array/Lists

Given a simple Matrix implementation

class Matrix(val matrix: Array[Array[Double]]) {
...
 开发者_开发知识库 def add(scalar:Double) { matrix.map(_.map( _ + scalar )) }
  def set(row:Int,col:Int,value:Double) { matrix(row)(col) = value }
...
}

To my understanding Mutability means I can't reassign matrix but I can set new values within it. As demonstrated by set() working.

The implementation of add right now is broken, but i'm stuck as to how to best implement it. I was hopeful about using transform

def add(scalar:Double) { matrix.transform(_.transform( _ + scalar )) }  
// type mismatch; found : ...WrappedArray[Double] required: Array[Double]

But I can't get it to compile yet. So is there a way to get above example to work?

And please feel free to hammer any flaws in my logic about list/array mutability :P


Indeed, you can't reassign to matrix, because it is a val (the reference is immutable). Instances of Array can be changed, because the interface of Array so allows, which makes it a mutable class.

So matrix = is not allowed. The call with matrix.map is valid, it creates a new array, leaving matrix untouched. It also changes the sub arrays inside matrix, because of the second map. Not what you want. Finally, the result is not assignable to matrix, because assignments to matrix are not allowed

transform is indeed the way to go. But the arrays you want to make changes in are the ones in matrix (the lines), not matrix itself, which should still contain the same (but changed) lines. The proper call is

matrix.foreach(_.transform(_ + scalar)

Yet, your version should have worked. transform returns the target of the call. The point is that you can chain calls, a.transform(...).doSomethingElse().andAgain() (which you do not need here). So your matrix.transform should have been a transform(identity) - with the side effect that this particular identity would change the content of the lines, and that would have been fine.

The problem is that transform is not really a method of Array (arrays are in the JVM and have no such method). It comes from an implicit conversion. There are two notable implicit conversions from Array, one to ArrayOps, another one to WrappedArray (details in the article Fighting Bit Rot with Types, towards the end). Method transform is in WrappedArray. Its return type has to be WrappedArray, because transform is defined well above in the type hierarchy, and forces the result to be this. Which means the not too interesting result of transform should not be used for arrays. So you must go with foreach.


You need to do something with the return value of the matrix.map(_.map( _ + scalar )). Create a new matrix based on this value and return it:

def add(scalar:Double) = { new Matrix(matrix.map(_.map( _ + scalar ))) }

You can't assign to matrix again, since this is a property of val(unability to assign a new value).
The usage is then:

val matrix = new Matrix(Array(Array(1,2)))
val newMatrix = matrix.add(5)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜