A lot of new Ruby developers I’ve worked with have seen the symbol notation—starting with a :— and have been confused by what a symbol actually is. There is a lot of information out there that is confusing as well. Here’s a brief rundown of what symbols are and how they are used.
What a Symbol is and What it is not
When I first encountered symbols, someone told me that they were a simplified String without as much of the baggage. This isn’t the case. The Symbol class doesn’t inherit from the String class, nor does the String class inherit from the Symbol class.
According to The Ruby Way symbols actually have an immediate value, like Fixnum’s (numbers). Strings are like any other object. Each string is an instance of the String class. What this really means is that in the following example, the strings are stored in different locations in memory and the symbols refer to the same immediate value in memory.
Now that we’ve established that symbols aren’t strings, but a series of characters representing an immediate value, the real question is how to use them.
How We Use Symbols
There are a couple of common uses for symbols. They are by no means the only use for symbols and they aren’t uses exclusive to symbols.
As Keys for Hashes
A hash object is like an array except the index or key for each element in the hash is another object. For example, you can have a hash like this.
class Person
attr_accessor :name
def initialize(name)
@name = name
end
end
dave = Person.new("Dave")
julie = Person.new("Julie")
joe = Person.new("Joe")
nikki = Person.new("Nikki")
girlfriends = { joe => nikki, dave => julie }
This example is a little contrived, but it shows that if you know about the object identified by the variable ‘joe’, you can find out that his girlfriend is ‘nikki.’
girlfriends[joe] #=> returns nikki
In most cases, having this kind of object as the key in a hash is overkill. If we know about joe, why not use a string or symbol as they key for the hash. After all, his name is “Joe.”
girlfriends = { :joe => nikki, :dave => julie }
girlfriends[:joe]
In this example, you still get the Person object back identifying Nikki, but in this case we don’t have the overhead of an object in the key or the hassle of making sure that this object representing Joe is an exact match to the one in the hash.
Symbols are also typically used in hashes identifying arguments passed to a method call. An excellent explanation of the best approach to this is in Chapter 2 of Ruby Best Practices.
Here’s a quick example from Ruby on Rails.
User.find(:all, :conditions => "active = 1", :include => [:posts, :friends])
ActiveRecord classes accept a hash as a parameter on the find method to identify what it is looking for in the query string. This also demonstrates the other two uses I’ll be covering in this post: as flags—representing certain behavior or state— and representing classes or methods.
As Flags—Representing Behavior or State
Have you ever managed a user system and used magic numbers to represent whether the user was pending, active, inactive, or deleted? 0, 1, 2, and 3 are simply not very descriptive. Wouldn’t it be nice to instead have the state represented by an object with an immediate value that was readable? Enter symbols!
user = User.new user.status = :pending
This has two nice advantages. First, :pending means the same thing across your entire application as far as Ruby goes. So, there’s no going out of scope, etc. Second, you don’t have to answer the question “What’s the user’s status?” with “0, um, I mean ‘pending’.”
This covers state, but what about behavior? Let’s go back to our ActiveRecord example.
User.find(:all, :conditions => "active = 1", :include => [:posts, :friends])
The first argument :all, is not part of the hash. It represents the behavior—finding all users that match our conditions—that we want the find method to exhibit. Passing :first in there would produce a different result.
Representing a Class or Method
The best examples I can think of for classes come from Ruby on Rails and ActiveRecord. In an ActiveRecord object, you declare associations with other classes by representing the associated classes as symbols.
class User < ActiveRecord::Base has_and_belongs_to_many :roles belongs_to :group has_many :friends
:roles, :group, and :friends represent the Role, Group, and Friend classes.
Symbols represent methods in all kinds of places. This is usually done to call or find something out about the method. Here are some quick examples:
# Does the object have a method called jump? object.respond_to?(:jump) #=> returns true if the method exists # Call the private method initialize (this is usually only called by the "new" method) # This is not a good idea on an object. object.send(:initialize)
In Place of Strings
Despite the fact the symbols are not strings, in many cases—especially when parameters on a method— you can pass a string or a symbol. The two are basically interchangeable as long as you’re willing to call .to_sym on strings and .to_s on symbols.
You can’t always interchange strings and symbols, so be careful with this.




