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

Discussion in 'Ruby' started by timr, Dec 29, 2009.

  1. timr

    timr Guest

    #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# # # # # #"
    # >> "# # ##### ##### # # ### # # ####### #"
    # >> "# # # # # # # # # # # #"
    # >> "# ### ### # # # # ##### # # # ##### #"
    # >> "# # # # # # #"
    # >> "#####################################"
     
    timr, Dec 29, 2009
    #1
    1. Advertising

  2. timr

    Seebs Guest

    On 2009-12-29, timr <> 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
    --
    Copyright 2009, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Dec 29, 2009
    #2
    1. Advertising

  3. timr

    timr Guest

    On Dec 28, 9:41 pm, Seebs <> wrote:
    > On 2009-12-29, timr <> 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.


    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


    >
    > -s
    > --
    > Copyright 2009, all wrongs reversed.  Peter Seebach / ://www.seebs.net/log/<-- lawsuits, religion, and funny pictureshttp://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    timr, Dec 29, 2009
    #3
  4. timr

    Seebs Guest

    On 2009-12-29, 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:


    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 /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Dec 29, 2009
    #4
  5. timr

    Josh Cheek Guest

    [Note: parts of this message were removed to make it a legal post.]

    On Mon, Dec 28, 2009 at 11:40 PM, timr <> wrote:

    > #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.
     
    Josh Cheek, Dec 29, 2009
    #5
  6. 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

    --
    Phillip Gawlowski
     
    Phillip Gawlowski, Dec 29, 2009
    #6
  7. timr

    timr Guest

    On Dec 28, 10:20 pm, Seebs <> wrote:
    > On 2009-12-29, 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:

    >
    > 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 / ://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.
     
    timr, Dec 29, 2009
    #7
  8. > #dup creates a copy of an object with a different object_id. As
    > follows:

    <=E2=80=A6>

    >> a =3D ["bar", "baz"]

    =3D> ["bar", "baz"]
    >> b =3D a.dup

    =3D> ["bar", "baz"]
    >> c =3D Marshal.load(Marshal.dump(a))

    =3D> ["bar", "baz"]
    >> b[0] << "s"

    =3D> "bars"
    >> b

    =3D> ["bars", "baz"]
    >> a

    =3D> ["bars", "baz"]
    >> c

    =3D> ["bar", "baz"]
    >> a.object_id

    =3D> 2157344160
    >> b.object_id

    =3D> 2157338800
    >> c.object_id

    =3D> 2157328340
    >> a[0].object_id

    =3D> 2157344140
    >> b[0].object_id

    =3D> 2157344140
    >> c[0].object_id

    =3D> 2157328320

    Regards,
    Rimantas
    --
    http://rimantas.com
     
    Rimantas Liubertas, Dec 29, 2009
    #8
  9. timr

    Seebs Guest

    On 2009-12-29, timr <> 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
    --
    Copyright 2009, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
     
    Seebs, Dec 29, 2009
    #9
  10. timr

    timr Guest

    On Dec 28, 10:49 pm, Rimantas Liubertas <> 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


    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.
     
    timr, Dec 29, 2009
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. KK
    Replies:
    2
    Views:
    596
    Big Brian
    Oct 14, 2003
  2. Replies:
    7
    Views:
    302
    codergem
    May 29, 2006
  3. Replies:
    5
    Views:
    331
    Jim Langston
    May 30, 2006
  4. François Beausoleil

    :s.respond_to?(:dup) && :s.dup raises

    François Beausoleil, Apr 5, 2007, in forum: Ruby
    Replies:
    1
    Views:
    101
    Tim Hunter
    Apr 5, 2007
  5. Luka Stolyarov
    Replies:
    10
    Views:
    295
    Thomas Sondergaard
    Sep 11, 2010
Loading...

Share This Page