til: Ruby's hashmap syntax

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.

If you want to hear when I publish more, sign up for my mailing list!

    previous

    < Don't make Emacs keymaps -- define them.
    tag: til
    tag: ruby