Skip to content

Instantly share code, notes, and snippets.

@ryansobol
Last active August 6, 2024 14:51
Show Gist options
  • Save ryansobol/9b0b6995a7ae806cd008 to your computer and use it in GitHub Desktop.
Save ryansobol/9b0b6995a7ae806cd008 to your computer and use it in GitHub Desktop.
Symbols in Ruby

What's a Symbol and why is it imporant?

In Ruby, a Symbol is the most efficient way, in terms of time and memory, to represent a set of characters.

What does a Symbol look like?

Most commonly, a Symbol is a single word prefixed by a colon:

:hello

NOTE: You'll see an example of a multi-word Symbol later.

When calling puts on a Symbol:

puts :hello

It displays the following:

hello

But when calling p on this Symbol:

p :hello

It displays the following:

:hello

How does a Symbol compare to a String?

A String can be assigned to a variable:

name = 'john'

Similarly, a Symbol can be assigned to a variable too:

name = :john

Also, a String can receive a variety of methods:

name = 'john'
name = name.upcase  #=> 'JOHN'

In this example, a copy of the 'john' String was created where each letter was capitalized to form 'JOHN'. Afterwards, the 'JOHN' String was reassigned to the name variable, replacing 'john'. In other words, two unique Strings were created.

Similarly, a Symbol can receive a variety of methods too:

name = :john
name = name.upcase  #=> :JOHN

In this example, a copy of the :john Symbol was created where each letter was capitalized to form :JOHN. Afterwards, the :JOHN Symbol was reassigned to the name variable, replacing :john. In other words, two unique Symbols were created.

How does a Symbol contrast to a String?

A String is mutable. That means its value can change while a program is running:

name = 'john'
name.upcase!  #=> 'JOHN'

In this example, the 'john' String itself was capitalized to 'JOHN'. No copies were made. And because only the value of the String has changed, the name variable doesn't need to be reassigned. In other words, one String was created and altered.

Unlike a String, a Symbol is immutable. That means its value remains constant during the entirety of the program:

name = :john
name.upcase!  # NoMethodError: undefined method `upcase!' for :john:Symbol

In this example, there is no upcase! method for the :john Symbol. It's not possible to change the value of a Symbol like you can a String. In other words, once created, a Symbol cannot be altered.

When do you use a Symbol?

Strings with the same content refer to a different object:

'john'.object_id  #=> 927900
'john'.object_id  #=> 928360

In contrast, Symbols with the same content refer to the same object:

:john.object_id  #=> 539688
:john.object_id  #=> 539688

In other words, two Strings with the exact same content are two different objects. However, two Symbols with the exact same content are only one object.

Every time a program creates an object, it takes time and memory. This means Symbols are more efficient than Strings.

For this reason, Symbols make great Hash keys:

person = { :name => 'john' }

person[:name]  #=> 'john'

In this example, the first time the Ruby interpreter sees :name, it creates a Symbol. The next time it encounters :name, it reuses the same Symbol saving precious time and memory.

In fact, this is so common, there's a shorthand way of writing the above example:

person = { name: 'john' }

person[:name]  #=> 'john'

In this example, the colon moved to the right of the word name and the hash rocket => disappeared.

TIP: This syntax for Symbols, where the colon is to the right of the word, is only available when defining a Hash using curly braces {}.

When do you use a String?

If Symbols are more efficient than Strings, why bother with Strings at all?

One reason is that Strings have a richer set of methods.

For example, two Strings can be added together, but two Symbols cannot.

'jo' + 'hn'  #=> 'john'
:jo + :hn  # NoMethodError: undefined method `+' for :jo:Symbol

A String can be centered, while a Symbol cannot.

'john'.center(6)  #=> ' john '
:john.center(6)  # NoMethodError: undefined method `center' for :john:Symbol

A String can be queried about its content, but a Symbol cannot.

'john'.include?('jo')  #=> true
:john.include?(:jo)  # NoMethodError: undefined method `center' for :john:Symbol

Strings have many methods, like the ones above, that make working with textual content much easier.

How do you convert a String to a Symbol and vice versa?

Quite easily, actually:

'john'.to_sym  #=> :john
:john.to_s  #=> 'john'

In both cases, a copy is made of the content and either a new Symbol or String is returned.

What does a multi-word Symbol look like?

Less commonly, a Symbol is also multiple words, wrapped inside quotation marks and prefixed by a colon:

:'john lennon'

When calling puts on a multi-word Symbol:

puts :'john lennon'

It displays the following:

john lennon

But when calling p on this Symbol:

p :'john lennon'

It displays the following:

:"john lennon"

NOTE: Ruby always uses double quotation marks when displaying multi-word Symbols.

@kayeon
Copy link

kayeon commented Oct 23, 2014

yay! learnin' about Symbols :)
little chunks really help... thanks!

@jmongrel
Copy link

You have a potential to become a teacher or a book author. Keep it up!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment