March 2024
I was writing some Ruby for the first time, and I made a hashmap with some data in it.
map1 = {"foo": 1, "bar": 2}
I was then surprised to find out that I couldn't get any items out of it.
> map1 = {"foo": 1, "bar": 2}
> map1["foo"]
=> nil
Heck, it didn't even seem to have the key stored in it!
> map1 = {"foo": 1, "bar": 2}
> map1.has_key?("foo")
=> false
So I dug a bit into the documentation. The problem is there are two syntaxes for creating hashmap literals, a json-like syntax, and what Ruby calls the "rocket" syntax.
map1 = {"foo": 1, "bar": 2} # the json-like syntax
map2 = {"foo" => 1, "bar" => 2} # "rocket" syntax
The json-like syntax is newer, and is the cause of my confusion. It silently converts each string key to a symbol.
> map1 = {"foo": 1, "bar": 2}
> map1.keys
=> [:foo, :bar]
The rocket syntax doesn't!
> map2 = {"foo" => 1, "bar" => 2}
> map2.keys
=> ["foo", "bar"]
So, for any maps created by the json-like syntax, they must be accessed with symbols.
> map1 = {"foo": 1, "bar": 2}
> map1[:foo]
=> 1
Or, just create them with the rocket syntax, and you can access them with strings. Like you expect.
I don't understand why this is the case. This conversion is surprising, especially since the json-like syntax is a newer addition to Ruby.