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# # # # # #"
# >> "# # ##### ##### # # ### # # ####### #"
# >> "# # # # # # # # # # # #"
# >> "# ### ### # # # # ##### # # # ##### #"
# >> "# # # # # # #"
# >> "#####################################"

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 2009-12-29, timr <timrandg@gmail.com> wrote:

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

--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!

#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]

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 Mon, Dec 28, 2009 at 11:40 PM, timr <timrandg@gmail.com> wrote:

#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

···

--
http://rimantas.com

> 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.

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 Dec 28, 9:41 pm, Seebs <usenet-nos...@seebs.net> wrote:

On 2009-12-29, timr <timra...@gmail.com> wrote:

-s
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nos...@seebs.nethttp://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

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 Dec 28, 10:49 pm, Rimantas Liubertas <riman...@gmail.com> wrote:

> #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
--http://rimantas.com

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 2009-12-29, timr <timrandg@gmail.com> wrote:
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!

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

···

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:

--
Phillip Gawlowski

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

···

On Dec 28, 10:20 pm, Seebs <usenet-nos...@seebs.net> wrote:

On 2009-12-29, timr <timra...@gmail.com> 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
--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nos...@seebs.nethttp://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!

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

-s

···

On 2009-12-29, timr <timrandg@gmail.com> wrote:

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

--
Copyright 2009, all wrongs reversed. Peter Seebach / usenet-nospam@seebs.net
| Seebs.Net <-- lawsuits, religion, and funny pictures
Fair game (Scientology) - Wikipedia <-- get educated!