Odd behavior when << hash

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.

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

“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

can see that it has its own value, acquired randomly.

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 B.
[email protected] http://AgileConsultingLLC.com/
[email protected] http://GaslightSoftware.com/

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, Sep 22, 2010 at 2:33 PM, Alex S. [email protected] wrote:

“result” => “true”
p “Final steps list: #{setup.inspect}”
around it?

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

On 22.09.2010 21:51, Alex S. 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

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs