On Thu, Sep 10, 2009 at 12:20 AM, Yossef Mendelssohn<ymendel / pobox.com> wrote:

> Mason, you're going to want to make an actual copy of the original
> variable, not simply a new pointer to it (which is what you get when
> you do something like `b = a`).

I think it's a good thing for a ruby learner to get the distinction
between variables and objects straight.

http://talklikeaduck.denhaven2.com/2006/09/13/on-variables-values-and-objects

You don't copy variables, you copy objects, so I'd restate that as
"you're going to want to make a copy of the object referenced by the
original variable."  It's subtle I admit but it helps to start
thinking that way explicitly when dealing with languages with object
reference semantics.

> In many cases, calling .dup or .clone
> will work. (As in `b = a.dup` or `b = a.clone`.)
>
> However, since you have an array of arrays, you're going to need a
> "deep copy". I believe `b = Marshal.load(Marshal.dump(a))` is the
> standard idiom.

In this case, it's probably not a bad idea to consider writing a more
'domain specific class'  This took me a minute or two to refactor the
example code:

class Array2D
  def initialize(rows)
    @rows = rows
  end

  def self.[](*rows)
    new(rows)
  end

  def [](row,col)
    @rows[row][col]
  end

  def []=(row,col,val)
    @rows[row][col] = val
  end

  def to_s
    @rows.map {|row| row.join(", ")}.join("\n")
  end

  def dup
    Array2D.new(@rows.map {|row| row.dup})
  end
end

current_state = Array2D[[1, 3, 6], [5, 0, 2], [4, 7, 8]]
new_state = current_state.dup
puts "Current State:"
puts current_state.to_s
puts "current_state[1, 1] is "  + current_state[1, 1].to_s
puts "current_state[2, 1] is "  + current_state[2, 1].to_s
# Exchange positions
new_state = current_state.dup
new_state[1, 1] = current_state[2, 1]
new_state[2, 1] = current_state[1, 1]

# Show changed values
puts "New State:"
puts new_state.to_s
puts "New State[1, 1] = " + new_state[1, 1].to_s
puts "New State[2, 1] = " + new_state[2, 1].to_s

# Current State should be unchanged
puts "Current State:"
puts current_state.to_s
puts "current_state[1, 1] is "  + current_state[1, 1].to_s
puts "current_state[2, 1] is "  + current_state[2, 1].to_s


When run this outputs:

Current State:
1, 3, 6
5, 0, 2
4, 7, 8
current_state[1, 1] is 0
current_state[2, 1] is 7
New State:
1, 3, 6
5, 7, 2
4, 0, 8
New State[1, 1] = 7
New State[2, 1] = 0
Current State:
1, 3, 6
5, 0, 2
4, 7, 8
current_state[1, 1] is 0
current_state[2, 1] is 7


-- 
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale