43

Using Ruby 2.3:

In example 1, the string key "a" is automatically converted to a symbol, whereas with example 2, it stays a string.

Example 1

{"a": 1}
# => {:a=>1} 

Example 2

{"a"=>"c"}
# => {"a"=>"c"}

I thought : was the same as the old style hash rocket => syntax. What is going on? Why have I never noticed this in Rails? Is it the HashWithIndifferentAccess that is obscuring this?

ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
Nona
  • 5,302
  • 7
  • 41
  • 79
  • @Zabba Why did you need to add that version? It only works in recent Rubys. If the OP says it works, it entails that it is a recent version. – sawa Apr 09 '16 at 08:23
  • 2
    The OP mentioned that version in the question so it is not appropriate to remove it since removing it would change the meaning and intent of the question, so just being original here. – Zabba Apr 09 '16 at 08:27
  • 1
    It's not a string key, it's a symbol key. Nothing is being changed. – Jörg W Mittag Apr 09 '16 at 12:00

3 Answers3

52

In Ruby 2.3(.0), these are all the same:

{:"a" => 1}
{"a": 1},
{:a => 1}
{a: 1} 

They all translate to the same thing: a is a symbol in all these cases.

{"a"=>1} is different: a is a string in this case.

Zabba
  • 64,285
  • 47
  • 179
  • 207
10

It's because of the new hash syntax introduced with ruby 1.9. The syntax with colon works with symbol keys only. It's called a "symbol to object" hash and it's only syntactic sugar for the most common style of hashes out there. Another point for me, it's closer to the javascript object notation.

If I have mixed key types then I prefer the old style (hash-rocket syntax), but that's up to you. Mixing the two style looks ugly to me.

guitarman
  • 3,290
  • 1
  • 17
  • 27
  • 3
    This isn't the syntax introduced in ruby 1.9. – sawa Apr 09 '16 at 07:42
  • It is not close to the javascript notation. Javascript does not distinguish strings and symbols. – sawa Apr 09 '16 at 07:53
  • 3
    @sawa the new syntax was introduced in ruby 1.9 and it is closer to the javascript notation. – Reyko Apr 09 '16 at 08:16
  • @Reyko I see. So you know a lot lot more than me. LOL LOL. – sawa Apr 09 '16 at 08:19
  • @Zabba Perhaps your comment is not understood by these people. You better change it to "It was the ... syntax that was ...". – sawa Apr 09 '16 at 08:21
  • 6
    I might also add here that the `{"a": 1}` notation *looks* exactly like JSON, but does not behave like it. In ruby we have symbols, and `"a":` translates to a Ruby symbol (not a string); in Javascript we don't have symbols, so in the JSON version of `{"a":1}`, "a" is a string. So while the Ruby hash notation in question looks like JSON, it technically is not the same. – Zabba Apr 09 '16 at 08:26
  • @Zabba we agree :) – Reyko Apr 09 '16 at 08:27
  • @Zabba Exactly. But there seems to be one super clever person beyond our understanding. – sawa Apr 09 '16 at 08:28
  • 2
    @sawa I don't need to know more than you. I just know the basics – Reyko Apr 09 '16 at 08:30
  • 3
    @Reyko, in case you were wondering, sawa's LOL is sort of like [this](http://www.talkingwav.com/various/evilaugh.wav). – Cary Swoveland Apr 09 '16 at 08:35
  • @CarySwoveland nice one :) – Reyko Apr 09 '16 at 08:44
  • 1
    @sawa, the colon syntax for hashes was indeed added in Ruby 1.9. – Zabba Apr 10 '16 at 08:16
  • @Zabba Yes indeed. And the question is not about `foo:`, is it about `"foo":`. – sawa Apr 10 '16 at 09:07
1

According to Ruby documentation:

Blockquote Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. [...]

This means that running:

$ ruby -e ruby -e "h = {key: \"value\"}; puts h"
$ ruby -e ruby -e "h = {:key => \"value\"}; puts h"
$ ruby -e ruby -e "h = {\"key\": \"value\"}; puts h"
$ ruby -e ruby -e "h = {:\"key\" => \"value\"}; puts h"
$ ruby -e ruby -e "h = {\"#{:key}\": \"value\"}; puts h"

Will produce the same result:

$ {:key=>"value"}
renatodamas
  • 16,555
  • 8
  • 30
  • 51