ridiculous behavoir of Array#push and Array#clear

Discussion in 'Ruby' started by hongseok.yoon@gmail.com, Mar 8, 2006.

  1. Guest

    See bellow code please.

    1 obj1 = "object1"
    2 obj2 = "object2"
    3 obj3 = "object3"
    4
    5 arr1 = Array.new
    6 arr2 = Array.new
    7
    8 arr1 << obj1
    9 arr1 << obj2
    10
    11 arr2 << obj3
    12
    13 puts "<arr1>"
    14 arr1.each {
    15 | element |
    16 puts element
    17 }
    18
    19 puts "<arr2>"
    20 arr2.each {
    21 | element |
    22 puts element
    23 }
    24
    25 arr1.push( arr2 )
    26 puts "<arr1 << arr2>"
    27 arr1.each {
    28 | element |
    29 puts element
    30 }
    31
    32 arr2.clear
    33 puts "<arr2.clear>"
    34
    35 puts "<arr2>"
    36 arr2.each {
    37 | element |
    38 puts element
    39 }
    40
    41 puts "<arr1>"
    42 arr1.each {
    43 | element |
    44 puts element
    45 }

    result is...

    <arr1>
    object1
    object2
    <arr2>
    object3
    <arr1 << arr2>
    object1
    object2
    object3
    <arr2.clear>
    <arr2>
    <arr1>
    object1
    object2

    In the last list of arr1, there's no object3. Why? Does Array#push()
    method append the array as a refrence? If so, why it does? And after
    arr2 had been cleared, I still can access to 3rd member of arr1 without
    exceptions or errors.

    Yes, I can use clone() method for Array#push. But before, I hope to
    know the reason why RUBY's Array#push method works like above.

    Thanks.
     
    , Mar 8, 2006
    #1
    1. Advertising

  2. Hannes Wyss Guest

    inspect will give you the answer:

    On 3/8/06, <> wrote:
    > 1 obj1 =3D "object1"
    > 2 obj2 =3D "object2"
    > 3 obj3 =3D "object3"
    > 4
    > 5 arr1 =3D Array.new
    > 6 arr2 =3D Array.new
    > 7
    > 8 arr1 << obj1
    > 9 arr1 << obj2
    > 10
    > 11 arr2 << obj3
    > 12
    > 13 puts "<arr1>"

    14 puts arr1.inspect
    -> [ "object1", "object2" ]

    > 19 puts "<arr2>"

    20 puts arr2.inspect
    -> [ "object3" ]

    > 25 arr1.push( arr2 )
    > 26 puts "<arr1 << arr2>"

    27 puts arr1.inspect
    -> [ "object1", "object2", [ "object3* ] ]
    # notice that the third Element of arr1 is not obj3, but arr2!

    > 32 arr2.clear

    # fine, emptying arr2...
    > 33 puts "<arr2.clear>"
    > 34
    > 35 puts "<arr2>"

    36 puts arr2.inspect
    -> [ ]

    > 41 puts "<arr1>"

    42 puts arr1.inspect
    -> [ "object1", "object2", [ ] ]
    # the third Element of arr1 is still arr2, it just has been cleared=
    ,
    # so not a trace of obj3...

    > Yes, I can use clone() method for Array#push. But before, I hope to
    > know the reason why RUBY's Array#push method works like above.

    ...or you could do:
    25 arr1.concat( arr2 )
    -> [ "object1", "object2", "object3" ]

    for any questions like that: try irb - I can only recommend it..

    hth

    Hannes
     
    Hannes Wyss, Mar 8, 2006
    #2
    1. Advertising

  3. ------=_Part_3258_30018097.1141809959323
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable
    Content-Disposition: inline

    > In the last list of arr1, there's no object3. Why? Does Array#push()
    > method append the array as a refrence?



    Yes, array elements are just references to objects pretty much in the same
    way a variable points to an object. In your case, when you push arr2 into
    arr1, what you're doing is making the 3rd element of the array be a
    reference to the object pointed to by the variable arr2:

    irb(main):006:0> arr1 =3D[]
    =3D> []
    irb(main):007:0> arr2 =3D[]
    =3D> []
    irb(main):008:0> arr1 << "object1"
    =3D> ["object1"]
    irb(main):009:0> arr1 << "object2"
    =3D> ["object1", "object2"]
    irb(main):010:0> arr2 << "object3"
    =3D> ["object3"]
    irb(main):011:0> arr1.push(arr2)
    =3D> ["object1", "object2", ["object3"]]

    irb(main):015:0> arr2.object_id # <=3D=3D=3D=3D arr2 and arr1[2] poi=
    nt to the
    same object
    =3D> 22439224
    irb(main):018:0> arr1[2].object_id
    =3D> 22439224


    > If so, why it does? And after
    > arr2 had been cleared, I still can access to 3rd member of arr1 without
    > exceptions or errors.




    The call to arr2.clear() clears the contents of the array object referenced
    by arr2, which happens to be the same array the 3rd element of arr1 points
    to:

    irb(main):012:0> arr2.clear
    =3D> []
    irb(main):013:0> arr1
    =3D> ["object1", "object2", []]


    The 3rd element is still in arr1, but now it just points to an empty array.

    Hope this helps,

    Martin

    ------=_Part_3258_30018097.1141809959323--
     
    Martin Traverso, Mar 8, 2006
    #3
  4. Pete Yandell Guest

    Changing your code to output the actual arrays:

    > obj1 = "object1"
    > obj2 = "object2"
    > obj3 = "object3"
    >
    > arr1 = Array.new
    > arr2 = Array.new
    >
    > arr1 << obj1
    > arr1 << obj2
    >
    > arr2 << obj3
    >
    > puts "<arr1>"
    > p arr1
    >
    > puts "<arr2>"
    > p arr2
    >
    > arr1.push( arr2 )
    > puts "<arr1 << arr2>"
    > p arr1
    >
    > arr2.clear
    > puts "<arr2.clear>"
    >
    > puts "<arr2>"
    > p arr2
    >
    > puts "<arr1>"
    > p arr1


    gives you:

    > <arr1>
    > ["object1", "object2"]
    > <arr2>
    > ["object3"]
    > <arr1 << arr2>
    > ["object1", "object2", ["object3"]]
    > <arr2.clear>
    > <arr2>
    > []
    > <arr1>
    > ["object1", "object2", []]


    which should give you a hint as to what's going on.

    Pete Yandell
     
    Pete Yandell, Mar 8, 2006
    #4
  5. This is because arr1 is storing a _reference_ to arr2. If you want to
    avoid this behaviour you could use any of the following:

    arr1 += arr2 (generates new array, old arr1 is now garbage)
    arr1 << arr2.dup (copies arr2, the copy is stored as an element of
    arr1)
    (arr1 << arr2).flatten! (ideal, but most verbose)

    The first two generate new objects. I believe the third doesn't (I may
    be wrong). Take your pick.
     
    Timothy Goddard, Mar 8, 2006
    #5
  6. In Message-Id: <>
    "Timothy Goddard" <> writes:

    > (arr1 << arr2).flatten! (ideal, but most verbose)
    >
    > The first two generate new objects. I believe the third doesn't (I may
    > be wrong). Take your pick.


    Or use Array#concat to concatenate two arrays destructively.

    irb(main):001:0> a1 = [0, 1, 2]
    => [0, 1, 2]
    irb(main):002:0> a2 = [3, 4, 5]
    => [3, 4, 5]
    irb(main):003:0> a1.concat(a2)
    => [0, 1, 2, 3, 4, 5]
    irb(main):004:0> a1
    => [0, 1, 2, 3, 4, 5]


    --
    March 9, 2006
    Dreams come true --- excepting yours.
     
    YANAGAWA Kazuhisa, Mar 8, 2006
    #6
    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. Markus Franz

    Processes with strange behavoir

    Markus Franz, Apr 4, 2004, in forum: Python
    Replies:
    2
    Views:
    342
    Peter Otten
    Apr 4, 2004
  2. Joachim Schmitz

    sscanf behavoir

    Joachim Schmitz, Apr 19, 2007, in forum: C Programming
    Replies:
    7
    Views:
    444
    Gunvant Patil
    Apr 20, 2007
  3. XyZaa
    Replies:
    0
    Views:
    573
    XyZaa
    Jul 19, 2007
  4. Sy Ys

    BackgrounDRb behavoir

    Sy Ys, May 27, 2007, in forum: Ruby
    Replies:
    1
    Views:
    111
    Ezra Zygmuntowicz
    May 27, 2007
  5. samppi
    Replies:
    27
    Views:
    496
    David A. Black
    Dec 5, 2007
Loading...

Share This Page