Symbol in Ruby
In the article, we’re going to explore the following topics:
- what’s a symbol in Ruby?
- the
Symbol
class - Symbols behind the scene
What’s a Symbol in Ruby?
A symbol is a unique instance of Symbol
which is generally used for identifying a specific resource. A resource can be:
- a method
- a variable
- a hash key
- a state
- etc…
A symbol is unique because only one instance of Symbol
can be created for a specific symbol in a running program
Here, we can see that the symbol :pending
is only created once as the two calls to :pending.object_id
return the same object identifier.
Symbols are often compared to strings. But the main difference between them relies on the fact that a new instance ofString
is created for each called string — even if they’re identical
Now that we’re more familiar with symbols let’s have a look to the Symbol
class and the API that it provides.
The Symbol class
This class is part of Ruby’s Core Library (a.k.a the core-lib
).
This class is not publicly instantiable
irb> Symbol.new
NoMethodError (undefined method `new' for Symbol:Class)
Otherwise, an instance of Symbol
is implicitly instantiated when a new symbol is declared
irb> :dummy_symbol.class
=> Symbol
Let’s have a look at its ancestor chain.
irb> Symbol.ancestors
=> [Symbol, Comparable, Object, Kernel, BasicObject]
Symbol
inherits from the default parent class Object
.
Note that it includes the Comparable
module.
This class shares the same ancestor chain as the String
and the Numeric
classes.
Feel free to read the
Ruby Object Model
article if you are unfamiliar with theObject
class and the ancestor chain.Feel free to read
The Comparable module
article if you are unfamiliar with theComparable
module.
This class also provides a set of interesting instance methods to compare, modify, and match symbols.
Most of the methods to modify and match symbols use the Symbol#to_s
method to work with the String
representation of the symbol.
Symbols behind the scene
As symbols are, for each of them, a unique instance of the Symbol
class then Ruby has to keep track of each of them to be able to ensure uniqueness.
To do so, Ruby provides an internal table named global_symbols
which is in charge of keeping track of all the symbols of your running program.
Note that symbols are only put into memory once. This makes them very efficient to use. But they stay in memory until the program exits. This is true for all the Ruby versions < 2.2.0. Otherwise, Symbols are Garbage Collected.
Symbol.all_symbols
returns an array that represents the content of the global_symbols
table at the moment of the method call
First, we can see that the global_symbols
table is not empty.
Indeed, at the program init, this table is filled in with all the methods, variables, and classes included in Ruby’s Core Library. These resources are inserted in the table as symbols.
For example, the
Struct
class is part of the Ruby’s Core Library.
Then, we can see that a symbol that represents a resource is added to the global_symbols
table when we define:
- a new symbol
- a new variable
- a new method
- a new class/module
Then, we can see that no new symbol is added to the table when we re-open the Hash
class. This is because the :Hash
symbol is already included in the global_symbols
table. This mechanism is the same for symbols, variables, and methods.
Note that this table is used any time that you’ve to deal with symbols.
Note that the
==
and===
operators are using an object-level comparison.But for all the other comparison’s methods, it uses the string representation of the symbol for comparison.
feel free to check this C macro for further information
RubyCademy’s Newsletter
In the RubyCademy newsletter, I share what I’m learning about Ruby & Rails, including helpful tips, code insights, and exclusive Ruby Cards with detailed explanations.
If it sounds helpful, feel free to subscribe for free:
Thank you for taking the time to read this message!