- The Two Faces of Strings
- Not Quite a String
- Optimized to Stand for Something
- In the Wild
- Staying Out of Trouble
- Wrapping Up
Optimized to Stand for Something
By now you have probably guessed that the Ruby String class is optimized for the data processing side of strings while symbols are meant to take over the "stands for" role—hence the name. Since we don't use symbols for data processing tasks, they lack most of the classic string manipulation methods that we talked about in Chapter 4. Symbols do have some special talents that make them great for being symbols. For example, there can only ever be one instance of any given symbol: If I mention :all twice in my code, it is always exactly the same :all. So if I have:
a = :all b = a c = :all
I know that a, b, and c all refer to exactly the same object. It turns out that Ruby has a number of different ways to check whether one object is equal to another,2 but with symbols it doesn't matter: Since there can only be one instance of any given symbol, :all is always equal to itself no matter how you ask:
# True! All true! a == c a === c a.eql?(c) a.equal?(c)
In contrast, every time you say "all", you are making a brand new string. So if you say this:
x = "all" y = "all"
Then you have manufactured two different strings. Since both the strings happen to contain the same three characters, the two strings are equal in some sense of the word, but they are emphatically not identically the same object. The fact that there can only be one instance of any given symbol means that figuring out whether this symbol is the same as that symbol is not only foolproof, it also happens at lightning speeds.
Another aspect of symbols that makes them so well suited to their chosen career is that symbols are immutable—once you create that :all symbol, it will be :all until the end of time.3 You cannot, for example, make it uppercase or lob off the second 'l'. This means that you can use a symbol with confidence that it will not change out from under you.
You can see all these issues at play in hashes. Since symbol comparison runs at NASCAR speeds and symbols never change, they make ideal hash keys. Sometimes, however, engineers want to use regular strings as hash keys:
author = 'jules verne' title = 'from earth to the moon' hash = { author => title }
So what would happen to the hash if you changed the key out from underneath it?
author.upcase!
The answer is that nothing will happen to the hash, because the Hash class has special defenses built in to guard against just this kind of thing. Inside of Hash there is special case code that makes a copy of any keys passed in if the keys happen to be strings. The fact that the Hash class needs to go through this ugly bit of special pleading precisely to keep you from coming to grief with string keys is the perfect illustration of the utility of symbols.