user = { name: "Alice", age: 30 }
puts user[:name] # Alice
puts user["name"] # nil
I'm 100% convinced that every Ruby developer has at least once made a bug where they tried to access a hash entry using a symbol, where the key was actually a string or vice-versa.
It would be great if Ruby would finally have immutable strings by default and, at that point, it would be possible to make symbols be strings.
This would prevent any such user[:name] vs user["name"] bugs while not breaking any other functionality. And also keeping the memory "optimized" by reusing a single immutable string.
> I'm 100% convinced that every Ruby developer has at least once made a bug where they tried to access a hash entry using a symbol, where the key was actually a string or vice-versa.
Yeah, that is true. It adds a cognitive load onto the ruby developer writing the code as well. Personally I prefer symbols as keys in a Hash, mostly because I like symbols, I assume it may be faster usually (this depends on factors, such as how many symbols one uses, the garbage collection kicking off and so forth, but by and large I think for most use cases, Symbols are simply more efficient). We also have abominations such as HashWithIndifferentAccess; Jeremy wrote an article why that is not good (indirectly, e. g. the article he wrote was about Symbols more, their use cases and differences to Strings, but from this it follows that HashWithIndifferentAccess is not a good idea. While I agree, I think some people simply don't want to have to care either way).
If I need to query a hash often, I tend to write a method, and the method then makes sure any input is either a string or a symbol for that given Hash.
> It would be great if Ruby would finally have immutable strings by default
But it has. I still use "# frozen_string_literal: true", but if you omit it, the Strings are frozen by default. People could set "# frozen_string_literal: true" in a .rb file if they want to retain the old behaviour.
> it would be possible to make symbols be strings.
But Symbols are not Strings. And bugs based on x[:foo] versus x['foo'] are always going to happen. They are very easy to avoid though. I don't really run into these in my own code, largely because I settled on symbols as keys for a Hash.
> And also keeping the memory "optimized" by reusing a single immutable string.
But a Symbol is not a String. Not even an immutable String. I understand what you mean (and internally it may be that way already, actually), but it is not a String.
I also prefer symbols as keys in hash. It just looks more aesthetically pleasing. :)
I think the optimization string vs symbol is negligent in most of the apps. If you need that level of optimization, you should probably switch to Rust.
> If I need to query a hash often, I tend to write a method, and the method then makes sure any input is either a string or a symbol for that given Hash.
This is terrible. This is the exact opposite of what Ruby is trying to achieve: developer happiness. You basically implement "symbol is a string" for hashes (aka HashWithIndifferentAccess).
> But it has. I still use "# frozen_string_literal: true", but if you omit it, the Strings are frozen by default.
This is not the case. If you omit "# frozen_string_literal: true", the strings are mutable, in all versions of Ruby, even in Ruby 4.0, which will be released on 25 Dec.
> But a Symbol is not a String. Not even an immutable String. I understand what you mean (and internally it may be that way already, actually), but it is not a String.
If it walks like a duck and quacks like a duck...
Who cares? What's the difference it makes for you whether symbols and string are interchangeable? Show me one valid use-case where having symbols and strings being different (user[:name] vs user["name"], or attr_reader "name") is useful.
Rails makes this more confusing with HashWithIndifferentAccess[1]. People coming from Rails are often confused by this when working with straight ruby and this kind of hash access doesn’t work.
Agreed. However had it should also be mentioned that this originated from rails.
Many bad things originate from the rails ecosystem. (Arguably some good too, but I am very pessimistic ever since shopify's recent powermove and DHH side-line commenting off-the-fence while being on shopify's board.)
> Symbols aren’t interchangeable though.
I'm 100% convinced that every Ruby developer has at least once made a bug where they tried to access a hash entry using a symbol, where the key was actually a string or vice-versa.It would be great if Ruby would finally have immutable strings by default and, at that point, it would be possible to make symbols be strings. This would prevent any such user[:name] vs user["name"] bugs while not breaking any other functionality. And also keeping the memory "optimized" by reusing a single immutable string.