Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does this ruby snippet work?

Tags:

ruby

hash

Conundrum:

something = {}
another = something
('a'...'f').each do |x|
  puts "another = #{another} and x= #{x} and something = #{something}"
  another = (another[x] ||= {})
end
puts something

Output:

=>another = {} and x= a and something = {}
=>another = {} and x= b and something = {"a"=>{}}
=>another = {} and x= c and something = {"a"=>{"b"=>{}}}
=>another = {} and x= d and something = {"a"=>{"b"=>{"c"=>{}}}}
=>another = {} and x= e and something = {"a"=>{"b"=>{"c"=>{"d"=>{}}}}}

Now at first glance it would seem like 'another' and 'something' are both pointing to the same hash object, but if that were case then in the output 'another' would match 'something'. So then how is the variable 'something' not an empty hash?

like image 334
nastycoder Avatar asked Feb 14 '23 01:02

nastycoder


1 Answers

In Ruby, everything is an object and all objects are passed around using pointers (there are exceptions, but they don't apply here). When you do

something = {}
another = something

a single Hash object is created and both variables point to that same object. When you do

another[x] ||= {}

a single Hash object is created and a pointer to that object is added to the Hash pointed to by another. Another way to write that would be

old_hash = another
new_hash = {}
old_hash[x] = new_hash
another = new_hash

Remember: all of those assignments are just moving around pointers to objects. It should now be clear that another is pointing to the new (empty) hash. However, since old_hash also contains a pointer to the new hash, any futures changes to the new hash (i.e. another) will be seen by old_hash. That is why something grows with each iteration.

Your example is really no different from this simple situation:

x = {}
y = {}
z = {}
x["a"] = y
y["b"] = z
z["c"] = {}
puts x
# {"a"=>{"b"=>{"c"=>{}}}}

Your example just reverses the last three assignments - which makes no difference to the result.

like image 81
Max Avatar answered Feb 25 '23 09:02

Max