I understand the theoretical difference between Strings and Symbols. I understand that Symbols are meant to represent a concept or a name or an identifier or a label or a key, and Strings are a bag of characters. I understand that Strings are mutable and transient, where Symbols are immutable and permanent. I even like how Symbols look different from Strings in my text editor.
What bothers me is that practically speaking, Symbols are so similar to Strings that the fact that they're not implemented as Strings causes a lot of headaches. They don't even support duck-typing or implicit coercion, unlike the other famous "the same but different" couple, Float and Fixnum.
The biggest problem, of course, is that hashes coming into Ruby from other places, like JSON and HTTP CGI, use string keys, not symbol keys, so Ruby programs have to bend over backwards to either convert these up front or at lookup time. The mere existence of HashWithIndifferentAccess
, and its rampant use in Rails and other frameworks, demonstrates that there's a problem here, an itch that needs to be scratched.
Can anyone tell me a practical reason why Symbols should not be frozen Strings? Other than "because that's how it's always been done" (historical) or "because symbols are not strings" (begging the question).
Consider the following astonishing behavior:
:apple == "apple" #=> false, should be true :apple.hash == "apple".hash #=> false, should be true {apples: 10}["apples"] #=> nil, should be 10 {"apples" => 10}[:apples] #=> nil, should be 10 :apple.object_id == "apple".object_id #=> false, but that's actually fine
All it would take to make the next generation of Rubyists less confused is this:
class Symbol < String def initialize *args super self.freeze end
(and a lot of other library-level hacking, but still, not too complicated)
See also:
Update: I think Matz makes the case for class Symbol < String
very well here: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192 (thanks to Azolo for digging this up, and also Matz' eventual retraction).
Symbols are immutable; Strings aren't. Being immutable means that the values won't change. Therefore, Symbols are faster than Strings.
Strings can be changed, symbols cannot. In the above example, I was able to change the value of the str variable by concatenating a new string to it. When I tried to do this to the sym variable, I got an undefined method error message, because symbols are immutable!
What is the difference between a symbol and a string? A string, in Ruby, is a mutable series of characters or bytes. Symbols, on the other hand, are immutable values. Just like the integer 2 is a value.
If you dynamically create lots of symbols, you are allocating a lot of memory that can't be freed until your program ends. You should only dynamically create symbols (using string.
This answer drastically different from my original answer, but I ran into a couple interesting threads on the Ruby mailing list. (Both good reads)
So, at one point in 2006, matz implemented the Symbol
class as Symbol < String
. Then the Symbol
class was stripped down to remove any mutability. So a Symbol
was in fact a immutable String
.
However, it was reverted. The reason given was
Even though it is highly against DuckTyping, people tend to use case on classes, and Symbol < String often cause serious problems.
So the answer to your question is still: a Symbol
is like a String
, but it isn't.
The problem isn't that a Symbol
shouldn't be String
, but instead that it historically wasn't.
I don't know about a full answer, but here's a big part of it:
One of the reasons that symbols are used for hash keys is that every instance of a given symbol is exact same object. This means :apple.id
will always return the same value, even though you're not passing it around. On the other hand, "apple".id
will return a different id every time, since a new string object is created.
That difference is why symbols are recommended for hash keys. No object equivalency test needs to be done when symbols are used. It can be short-circuited directly to object identity.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With