Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisbloom7/329281 to your computer and use it in GitHub Desktop.
Save chrisbloom7/329281 to your computer and use it in GitHub Desktop.
The hardest thing for me to grok in Ruby
colors = ["red"] #=> ["red"]
colors_2 = colors #=> ["red"]
colors_2 << "blue" #=> ["red", "blue"]
colors #=> ["red", "blue"]
def add_white (original_colors)
original_colors << "white"
end
add_white colors #=> ["red", "blue", "white"]
colors_2 #=> ["red", "blue", "white"]
@chrisbloom7
Copy link
Author

Apparently this is still difficult for me to grok 11 years later. Consider the following:

hash1 = { a: :some, b: :things }
hash2 = hash1
hash1[:a].object_id == hash2[:a].object_id # => true
hash1[:b].object_id == hash2[:b].object_id # => true
hash1[:a] = nil
hash2[:b] = nil
hash1 # => {:a=>nil, :b=>nil}
hash2 # => {:a=>nil, :b=>nil}

hash3 = { a: :some, b: :things }
hash3[:a] = hash3[:b]
hash3[:a].object_id == hash3[:b].object_id # => true
hash3[:b] = nil
hash3 # => {:a=>:things, :b=>nil}

Why does changing hash2 affect hash1, but changing hash3[:b] does not change hash3[:a]? With hash2 = hash1, both variables are now a pointer to the same object, so modifying via hash2 is the same as modifying via hash1 - they are one and the same. This was what I expected, but then I was thrown for a loop when hash3[:a] = hash3[:b] didn't work the same way.

The reason for that (as I currently understand it) is because each hash table entry maintains its own references. hash3[:a] = hash3[:b] is not saying that the entry for :a is one and the same with the entry for :b. They can contain the same object (as the object_id comparisons prove), but they are not pointers to each other's hash table entry.

So the memory location of hash3[:a] != the memory location of hash3[:b], but since they do contain the same object, if that object mutates it will mutate it for both entries since the two entries point to the same object 🤯. Consider:

hash4 = { a: "a", b: "b" }
hash4[:a] = hash4[:b]
hash4[:a].object_id # => 54600
hash4[:b].object_id # => 54600
hash4[:b].upcase!
hash4 # => {:a=>"B", :b=>"B"}

@chrisbloom7
Copy link
Author

TL;DR: hashes have some sharp edges because depending on assignment it is possible for them to mutate out from under you as you pass them around. It is also possible for them not to mutate out from under you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment