PLEASE HELP...dup is not working correctly in the following code

#dup creates a copy of an object with a different object_id. As
follows:

a = [1,2,3]
=> [1, 2, 3]

b = a.dup
=> [1, 2, 3]

b << 1000
=> [1, 2, 3, 1000]

a
=> [1, 2, 3]

b
=> [1, 2, 3, 1000]

Changing b does’t change a because b is a copy of a with a different
object_id.

However, unlike the irb session, the following code shows that
modification of the dupped object is somehow changing the original.
WTF? (you may want to change the font to courier to get the maze to
line up correctly). This behavior is so strange. I can see no
significant differences between the usage in the irb session and in
this code, yet the behavior is very different. Please explain if you
have any insights.
Thanks,
Tim

@maze1 = %{#####################################

# # #A # #

# # # # # ####### # ### # #######

# # # # # # #

##### # ################# #

# # # # # # #

##### ### ### # ### # # # # #

# # # # # B# # # # #

# ##### ##### # # ### # # #######

# # # # # # # # # #

### ### # # # # ##### # # # #####

# # # # #

#####################################}
class Maze
attr_accessor :maze

#initialize creates a @maze array with each row a sub array
def initialize(maze_name)
@maze = maze_name.split(/\n/).collect{|row| row.split(//)}
@maze_dup = @maze.dup
end
def write_(r, c)
@maze_dup[r][c] = “a”
end
def report
puts “@maze:”
@maze.each{|r| p r.join}
puts “@maze_dup:”
@maze_dup.each{|r| p r.join}
end
end

maze1 = Maze.new(@maze1)
maze1.report
maze1.write_(0,0)
maze1.report
maze1.write_(1,1)
maze1.report

>> @maze:

>> “#####################################”

>> “# # # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

>> @maze_dup:

>> “#####################################”

>> “# # # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

>> @maze:

>> “a####################################”

>> “# # # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

>> @maze_dup:

>> “a####################################”

>> “# # # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

>> @maze:

>> “a####################################”

>> “#a# # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

>> @maze_dup:

>> “a####################################”

>> “#a# # #A # # #”

>> “# # # # # # ####### # ### # ####### #”

>> “# # # # # # # # #”

>> “# ##### # ################# # #######”

>> “# # # # # # # # #”

>> “##### ##### ### ### # ### # # # # # #”

>> “# # # # # # B# # # # # #”

>> “# # ##### ##### # # ### # # ####### #”

>> “# # # # # # # # # # # #”

>> “# ### ### # # # # ##### # # # ##### #”

>> “# # # # # # #”

>> “#####################################”

On 2009-12-29, timr [email protected] wrote:

However, unlike the irb session, the following code shows that
modification of the dupped object is somehow changing the original.

No, it isn’t.

You have two separate arrays.

However, each of those arrays contains the same strings – the first
string
of each array is the same object.

You want a deep copy (where you duplicate all the objects in the array,
not just the arrays). Something like:

@maze_dup = @maze.map { |x| x.dup }

… I think.

-s

On Dec 28, 9:41 pm, Seebs [email protected] wrote:

of each array is the same object.

You want a deep copy (where you duplicate all the objects in the array,
not just the arrays). Something like:

@maze_dup = @maze.map { |x| x.dup }

… I think.

You are right about the strings having the same object_ids in each
object, which explains why the modification on the dupped object
affects the original strings. That helps. But the suggested strategy
doesn’t solve the problem:

a = [[‘a’, ‘b’], [‘c’,‘d’]]
=> [[“a”, “b”], [“c”, “d”]]

a.each{|r| r.each{|letter| p letter.object_id}}
4442750
4442740
4442710
4442700
=> [[“a”, “b”], [“c”, “d”]]

b = a.map{|r| r.each{|letter| letter.dup}}
=> [[“a”, “b”], [“c”, “d”]]

b.each{|r| r.each{|letter| p letter.object_id}}
4442750
4442740
4442710
4442700

Still the same object_ids for all of the contents.
Tim

On 2009-12-29, timr [email protected] wrote:

You are right about the strings having the same object_ids in each
object, which explains why the modification on the dupped object
affects the original strings. That helps. But the suggested strategy
doesn’t solve the problem:

Hmm.

a = [[‘a’, ‘b’], [‘c’,‘d’]]
=> [[“a”, “b”], [“c”, “d”]]

a.each{|r| r.each{|letter| p letter.object_id}}
4442750
4442740
4442710
4442700
=> [[“a”, “b”], [“c”, “d”]]

b = a.map{|r| r.each{|letter| letter.dup}}

This doesn’t seem right. The inner loop (which is the one I think
we care about) is using each, not map. So we never actually return
the array consisting of all the duplicated letters.

If you have an array of arrays, I think you need to use map at both
levels.

irb(main):001:0> a = [[‘a’, ‘b’], [‘c’,‘d’]]
=> [[“a”, “b”], [“c”, “d”]]
irb(main):002:0> b = a.map {|r| r.map{|l| l.dup}}
=> [[“a”, “b”], [“c”, “d”]]
irb(main):003:0> a.each{|r| r.each{|letter| p letter.object_id}}
2152912244
2152912216
2152912132
2152912104
=> [[“a”, “b”], [“c”, “d”]]
irb(main):004:0> b.each{|r| r.each{|letter| p letter.object_id}}
2152886456
2152886316
2152886232
2152886176
=> [[“a”, “b”], [“c”, “d”]]

What’s throwing you off here is that .each returns the array object
it started with.

So “r.each {…}” always returns r, unmodified.

-s

On Mon, Dec 28, 2009 at 11:40 PM, timr [email protected] wrote:

b
=> [1, 2, 3, 1000]

This is the difference

$ irb

a = [ ‘w’ , ‘x’ , ‘y’ ]
=> [“w”, “x”, “y”]

b = a.dup
=> [“w”, “x”, “y”]

a << ‘z’
=> [“w”, “x”, “y”, “z”]

b
=> [“w”, “x”, “y”]

a[0] << ‘x’
=> “wx”

a
=> [“wx”, “x”, “y”, “z”]

b
=> [“wx”, “x”, “y”]

a and b are different arrays, but they each contain the same objects.

I think the only way to make a deep copy is to explicitly dup everything
in
the array also, or to use marshall. I’m not sure why there isn’t a deep
copy
method.

On Dec 28, 10:20 pm, Seebs [email protected] wrote:

=> [[“a”, “b”], [“c”, “d”]]
the array consisting of all the duplicated letters.
2152912216
What’s throwing you off here is that .each returns the array object
it started with.

So “r.each {…}” always returns r, unmodified.

-s

Copyright 2009, all wrongs reversed. Peter S. / [email protected]://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

I was just going to post that correction after I realized that
mistake. Thanks for the help.

#dup creates a copy of an object with a different object_id. As
follows:
<…>

a = [“bar”, “baz”]
=> [“bar”, “baz”]

b = a.dup
=> [“bar”, “baz”]

c = Marshal.load(Marshal.dump(a))
=> [“bar”, “baz”]

b[0] << “s”
=> “bars”

b
=> [“bars”, “baz”]

a
=> [“bars”, “baz”]

c
=> [“bar”, “baz”]

a.object_id
=> 2157344160

b.object_id
=> 2157338800

c.object_id
=> 2157328340

a[0].object_id
=> 2157344140

b[0].object_id
=> 2157344140

c[0].object_id
=> 2157328320

Regards,
Rimantas

On 2009-12-29, timr [email protected] wrote:

I was just going to post that correction after I realized that
mistake. Thanks for the help.

Thanks for asking the question with enough detail, and illustrations,
that it was possible to help.

-s

On Dec 28, 10:49 pm, Rimantas L. [email protected] wrote:

=> [“bar”, “baz”]

c
=> 2157344140

c[0].object_id

=> 2157328320

Regards,
Rimantas
http://rimantas.com

This is in effect the deep copy of a complex array containing strings
that we were pining for. I think it is easier to do it this ways than
to map through all of the nested arrays. Thanks for the irb demo of
its use.

On 29.12.2009 07:15, timr wrote:

You are right about the strings having the same object_ids in each
object, which explains why the modification on the dupped object
affects the original strings. That helps. But the suggested strategy
doesn’t solve the problem:

irb(main):001:0> array = [“string”]
=> [“string”]
irb(main):002:0> array_dup = []
=> []
irb(main):003:0> array_dup[0] = array[0].clone
=> “string”
irb(main):004:0> array_dup[0].object_id
=> 30816948
irb(main):005:0> array[0].object_id
=> 30838824