Symbols

Learn what symbols are and how to use them in Ruby.

We'll cover the following

Define symbols

Symbols are similar to strings. Symbols are instances of the Symbol class, just as strings are instances of the String class). Here is how we can define a symbol in Ruby:

# assign symbol :something to variable "x"
x = :something

Compare the code above to the string’s definition:

x = "something"
x = 'something' # alternative syntax

Uses of symbols

We use symbols when, logically, a variable belongs to a set of similar values, for example:

order.status = :confirmed
order.status = :cancelled

The :confirmed symbol can be used in other parts of a program. But why are we using symbols in Ruby when the code above works well with strings? Consider:

order.status = 'confirmed'
order.status = 'cancelled'

It’s true. We often don’t have to use symbols. In some programming languages, there is no concept of symbols. However, there are a few reasons why a Ruby programmer may want to use symbols.

The first reason is that symbols are immutable. We can’t perform dangerous operations on them, but it’s possible to perform such operations on strings, like upcase!. In other words, by using symbols, we demonstrate our intent: This value is fixed, and there is probably a limited set of similar values.

It’s similar to a theatre ticket. We can write “Sectio A” by hand on every ticket, or we can use a rubber stamp for this purpose. Stamping takes fewer resources and is much faster. Moreover, every word written by hand is unique, like strings. They may look the same, but they are located in different computer memory parts. Conversely, stamped words are always the same and lead to only one source.

The second reason is that symbols are efficient and reusable and, because of immutability, the Ruby interpreter doesn’t need to allocate memory every time we create a new symbol. For example, if we have a string of something, which is nine characters, and we define this string in thousands of different places, the interpreter will use at least 9,000 bytes of memory when the program gets executed.

But that’s not the case with symbols. We allocate only one chunk of memory per symbol, so no matter how many definitions of something we have, we use only nine bytes of memory.

Technically speaking, references to the same symbols are always the same. References to the same strings aren’t always the same, but they can be the same.

Let’s try a tricky way to create an array of strings. For each create operation, we’ll be calling a block:

arr = Array.new(100) { 'something' } 

The code given above creates 100 strings of something. These strings are all different objects. Here is how we can verify that using the __id__ property of each object:

> arr[0].__id__
70100682145140
> arr[1].__id__
70100682144840

But when we create an array of symbols using the same trick, the result is different. The object identifier is always the same:

$ pry
> arr = Array.new(100) { :something }
...
> arr[0].__id__
2893788
> arr[1].__id__
2893788

In other words, an array of symbols has references to only one object.

Another benefit of symbols is that Ruby compares symbols by reference only. Reference is just a value like 0xDEADBEEF that fits into one of the CPU registers (4-8 bytes, depending on the architecture).

Try the commands given above in the terminal below.

Get hands-on with 1400+ tech skills courses.