Odd behavior when << hash

Discussion in 'Ruby' started by Alex Stahl, Sep 22, 2010.

  1. Alex Stahl

    Alex Stahl Guest

    Hi Folks - Using Ruby 1.8.7, I found this oddity:

    require 'rubygems'
    require 'json'

    setup = []
    ids = ["12345", "54321", "21345", "548752", "3215", "50203"]

    doIt = {
    "action" => "do something",
    "result" => "true"
    }

    cnt = rand(10)
    1.upto(cnt) do

    doIt['params'] = ids[rand(6)]
    p "Pushing step: #{doIt.inspect}"
    setup << doIt
    end

    p "Final steps list: #{setup.inspect}"

    **************************************

    When I inspect my final steps list at the end, the values of
    'doIt['params']' is always the same - set to the last value of the last
    run of the upto loop. But when I inspect doIt prior to pushing it, I
    can see that it has its own value, acquired randomly.

    So my question is, why is the hash not being pushed onto the array
    properly? What side effect am I encountering here and how do I get
    around it?

    (I've already tried declaring "params" => "" in the initial hash
    creation; that didn't help).

    Thanks,
    Alex

    PS - You'd be correct in noting this code doesn't do anything useful.
    I've stripped away other parts to isolate the questionable behavior for
    demonstration purposes.
    Alex Stahl, Sep 22, 2010
    #1
    1. Advertising

  2. On Sep 22, 2010, at 3:33 PM, Alex Stahl wrote:

    > Hi Folks - Using Ruby 1.8.7, I found this oddity:
    >
    > require 'rubygems'
    > require 'json'
    >
    > setup = []
    > ids = ["12345", "54321", "21345", "548752", "3215", "50203"]
    >
    > doIt = {
    > "action" => "do something",
    > "result" => "true"
    > }
    >


    # so here, doIt is referencing an object which is a hash

    > cnt = rand(10)
    > 1.upto(cnt) do
    >
    > doIt['params'] = ids[rand(6)]
    > p "Pushing step: #{doIt.inspect}"
    > setup << doIt


    # this puts that reference into the setup array
    # NOTE: it is always referring to the same hash

    > end
    >
    > p "Final steps list: #{setup.inspect}"
    >
    > **************************************
    >
    > When I inspect my final steps list at the end, the values of
    > 'doIt['params']' is always the same - set to the last value of the
    > last
    > run of the upto loop. But when I inspect doIt prior to pushing it, I
    > can see that it has its own value, acquired randomly.
    >
    > So my question is, why is the hash not being pushed onto the array
    > properly? What side effect am I encountering here and how do I get
    > around it?
    >
    > (I've already tried declaring "params" => "" in the initial hash
    > creation; that didn't help).
    >
    > Thanks,
    > Alex
    >
    > PS - You'd be correct in noting this code doesn't do anything useful.
    > I've stripped away other parts to isolate the questionable behavior
    > for
    > demonstration purposes.
    >
    >



    Try creating the hash object inside the loop (i.e., creating a new
    object each time)

    rand(10).times do
    setup << { "action" => "do something",
    "result" => "true",
    "params" => ids[rand(6)].dup
    }
    end
    puts "Final steps list: #{setup.inspect}"


    Note that I'm also calling .dup on the element taken from the ids
    array so there's a separate string object. You can apply this to your
    real code, I hope.

    -Rob

    Rob Biedenharn
    http://AgileConsultingLLC.com/
    http://GaslightSoftware.com/
    Rob Biedenharn, Sep 22, 2010
    #2
    1. Advertising

  3. Alex Stahl

    Alex Stahl Guest

    Thanks, Rob. Made the mistake of assuming I get a copy of the hash when
    I push it. IIRC, there are other (not-so-elegant) languages that do so.

    Appreciate the point about .dup as well, but since at the end of this,
    I'm just writing everything out to a file, and the elements of ids will
    never change (at least not in this script), I don't think I need a
    duplicate string.


    On Wed, 2010-09-22 at 14:43 -0500, Rob Biedenharn wrote:
    > On Sep 22, 2010, at 3:33 PM, Alex Stahl wrote:
    >
    > > Hi Folks - Using Ruby 1.8.7, I found this oddity:
    > >
    > > require 'rubygems'
    > > require 'json'
    > >
    > > setup = []
    > > ids = ["12345", "54321", "21345", "548752", "3215", "50203"]
    > >
    > > doIt = {
    > > "action" => "do something",
    > > "result" => "true"
    > > }
    > >

    >
    > # so here, doIt is referencing an object which is a hash
    >
    > > cnt = rand(10)
    > > 1.upto(cnt) do
    > >
    > > doIt['params'] = ids[rand(6)]
    > > p "Pushing step: #{doIt.inspect}"
    > > setup << doIt

    >
    > # this puts that reference into the setup array
    > # NOTE: it is always referring to the same hash
    >
    > > end
    > >
    > > p "Final steps list: #{setup.inspect}"
    > >
    > > **************************************
    > >
    > > When I inspect my final steps list at the end, the values of
    > > 'doIt['params']' is always the same - set to the last value of the
    > > last
    > > run of the upto loop. But when I inspect doIt prior to pushing it, I
    > > can see that it has its own value, acquired randomly.
    > >
    > > So my question is, why is the hash not being pushed onto the array
    > > properly? What side effect am I encountering here and how do I get
    > > around it?
    > >
    > > (I've already tried declaring "params" => "" in the initial hash
    > > creation; that didn't help).
    > >
    > > Thanks,
    > > Alex
    > >
    > > PS - You'd be correct in noting this code doesn't do anything useful.
    > > I've stripped away other parts to isolate the questionable behavior
    > > for
    > > demonstration purposes.
    > >
    > >

    >
    >
    > Try creating the hash object inside the loop (i.e., creating a new
    > object each time)
    >
    > rand(10).times do
    > setup << { "action" => "do something",
    > "result" => "true",
    > "params" => ids[rand(6)].dup
    > }
    > end
    > puts "Final steps list: #{setup.inspect}"
    >
    >
    > Note that I'm also calling .dup on the element taken from the ids
    > array so there's a separate string object. You can apply this to your
    > real code, I hope.
    >
    > -Rob
    >
    > Rob Biedenharn
    > http://AgileConsultingLLC.com/
    > http://GaslightSoftware.com/
    >
    >
    Alex Stahl, Sep 22, 2010
    #3
  4. Alex Stahl

    Josh Cheek Guest

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

    On Wed, Sep 22, 2010 at 2:33 PM, Alex Stahl <> wrote:

    > Hi Folks - Using Ruby 1.8.7, I found this oddity:
    >
    > require 'rubygems'
    > require 'json'
    >
    > setup = []
    > ids = ["12345", "54321", "21345", "548752", "3215", "50203"]
    >
    > doIt = {
    > "action" => "do something",
    > "result" => "true"
    > }
    >
    > cnt = rand(10)
    > 1.upto(cnt) do
    >
    > doIt['params'] = ids[rand(6)]
    > p "Pushing step: #{doIt.inspect}"
    > setup << doIt
    > end
    >
    > p "Final steps list: #{setup.inspect}"
    >
    > **************************************
    >
    > When I inspect my final steps list at the end, the values of
    > 'doIt['params']' is always the same - set to the last value of the last
    > run of the upto loop. But when I inspect doIt prior to pushing it, I
    > can see that it has its own value, acquired randomly.
    >
    > So my question is, why is the hash not being pushed onto the array
    > properly? What side effect am I encountering here and how do I get
    > around it?
    >
    > (I've already tried declaring "params" => "" in the initial hash
    > creation; that didn't help).
    >
    > Thanks,
    > Alex
    >
    > PS - You'd be correct in noting this code doesn't do anything useful.
    > I've stripped away other parts to isolate the questionable behavior for
    > demonstration purposes.
    >
    >
    >

    You are modifying the same hash, then adding the same hash to the array
    again. In other words, there is only ever one hash in your program (and data
    is mutable in Ruby).

    To analogize, if you record my address ten times, painting my shutters a
    different after each, then decide to visit each of the ten addresses that
    you have written down, you will find that all of the houses you visit will
    have the same colour of shutters as the final time you painted my house.

    I have modified the program to hopefully make this clearer.
    http://codepad.org/ZPB7UC6Q
    Josh Cheek, Sep 22, 2010
    #4
  5. On 22.09.2010 21:51, Alex Stahl wrote:
    > Thanks, Rob. Made the mistake of assuming I get a copy of the hash when
    > I push it. IIRC, there are other (not-so-elegant) languages that do so.
    >
    > Appreciate the point about .dup as well, but since at the end of this,
    > I'm just writing everything out to a file, and the elements of ids will
    > never change (at least not in this script), I don't think I need a
    > duplicate string.


    To complement the excellent explanations you have been given already:
    the technical term for the effect is "aliasing".

    http://en.wikipedia.org/wiki/Aliasing_(computing)#Aliased_pointers

    Kind regards

    robert

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
    Robert Klemme, Sep 23, 2010
    #5
    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. Elliot M. Rodriguez

    PLEASE HELP = odd TextChanged behavior

    Elliot M. Rodriguez, Oct 21, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    317
    Elliot M. Rodriguez
    Oct 22, 2003
  2. Michael Speer

    Odd behavior with odd code

    Michael Speer, Feb 16, 2007, in forum: C Programming
    Replies:
    33
    Views:
    1,069
    Richard Heathfield
    Feb 18, 2007
  3. rp
    Replies:
    1
    Views:
    500
    red floyd
    Nov 10, 2011
  4. Srijayanth Sridhar
    Replies:
    19
    Views:
    599
    David A. Black
    Jul 2, 2008
  5. Aldric Giacomoni

    Odd : a = Hash.new(Hash.new)

    Aldric Giacomoni, Nov 4, 2009, in forum: Ruby
    Replies:
    12
    Views:
    177
    Aldric Giacomoni
    Nov 5, 2009
Loading...

Share This Page