Just Another Victim of the Ambient Morality wrote:
>     Well, yeah, I got that.  It's just that he spent this whole paragraph
> on a rationale that wasn't true so I was wondering what he was really
> trying to get at for his rationale...

My rationale? Erm, the rationale stated by _others_ was that a matrix
(as a value) is immutable, therefore the implementation of a matrix (as
a data structure) should be immutable. But that makes no sense.

r ----------
| n0  n1  n2
| n3  n4  n5
| n6  n7  n8

What makes n0-n... special and different from just plain old n = 1?
Yes, r is a unit, but that just means that when n... is changed then r
is now a new value unit; you don't need to do that by constructing a
whole new matrix, you can do the same thing by changing members of r in
place. The _value_ of r at any given time is immutable, the data
structure that represents r need not be.

Given r:

r = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

Which is better?

def new_matrix(k, x, y, value)
  out = []
  k.each_with_index { |m, row|
    out << []
    m.each_with_index { |n, col|
      if row == x and col == y
        out[-1] << value
      else
        out[-1] << n
      end
    }
  }
  out
end
r = new_matrix(r, 2, 2, r[0][0])
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Or:

r[2][2] = r[0][0]
r # => [[0, 1, 2], [3, 4, 5], [6, 7, 0]]

Duh! The answer is obvious.

I do like Dave's idea about having a named method to do the in place
modification, though; that would make sure You Really Mean It and
eliminate the typo where you meant == but actually wrote =.

Ps. Paul gave another rationale: usefulness. That makes sense (though
its truth was contested). Dave also gave another rationale:
predictability. That makes sense too. But the immutability of the value
of a matrix as a rationale for disallowing destructive assignment to
members doesn't make sense.