Many programmers who are new to Ruby get confused when they see Ruby symbols. A lot us came to know about Ruby language through Ruby on Rails projects. In Ruby on Rails, symbols are everywhere! So it is essential to understand the concept of symbols in Ruby.
A symbol in Ruby is an instance of the class Symbol. A symbol is defined by prefixing a colon with an identifier. :name, :id, :user etc. are examples of symbols.
Let us see what is there in the class Symbol.
Symbol class in Ruby contains one class method all_symbols and instance methods id2name, inspect, to_i, to_int, to_s and to_sym.
- all_symbols – Returns an array of all the symbols in Ruby’s symbol table.
- id2name – Returns the string representation of the symbol – :name.id2name returns “name”.
- inspect – Returns the symbol literal
- to_i – Returns an integer unique for each symbol
- to_int – Same as to_i
- to_s - Same as id2name
- to_sym – Convert the symbol to a symbol!
Symbols are most commonly used in creating hashes. For example, consider the following hash,
We could have used strings instead of symbols in this case,
But the advantage in using symbols is the efficient use of memory. Maximum space taken by a symbol is never more than the space taken by an integer. This is because internally symbol is stored as an integer. In case of strings the memory space depends on the size of the string.
Also whenever a string is used in the program, a new instance is created. But for symbols, same identifier points to the same memory location! This can be easily checked by running the following,
The memory saved may look trivial in this case. But when a predefined hash key structure is used as parameter to a method and if the method is used many times in the program, the savings can be substantial! For example, in RoR a sample link is defined as,
The first parameter is the label used for the link and the second parameter is a hash. The second parameter is defined as a hash to enable dynamic parameters.
Now in the implementation of link_to method, a check is done to see if :action key exists in the hash and then corresponding value is used. Similarly :controller is also checked and if found is used. Hence using hashes is a good way to implement optional parameters.
In this example we could have used “controller” and “action” strings instead of symbols :controller and :action. But we will be missing two important advantages – efficient memory usage and speed of processing.
In a rails application, you might be using link_to hundreds of times. Assume that you have used it 10000 times in a big application. If we assume every call contained :controller and :action symbols, total memory required by the symbols = 2 * size of an integer. Whether we call link_to once or millions of times the memory taken remains same. But things would be different in case of strings as keys. Whenever a link_to is called 2 new strings “controller” and “action” will be created. Hence a total memory allocation of 10000*16 bytes would have done by Ruby interpreter (of course garbage collector will ensure memory usage at any point to be much less than this).
Second is the question of speed. We know that link_to internally compares hash key to :controller and :action. This is extremely fast since it is equivalent to comparing integers. But if we had used strings, comparison such as “controller”==”controller” is inefficient since it involves comparison of all the characters in it.
Strings are scoped and they get destroyed/garbage collected when the execution goes out of scope. But in case of symbols, they remain defined as long as the program is running. So if you have a very large number of symbols there could be a lot of unusable memory.
It is possible convert a string to symbol using the to_sym method. Hence “controller”.to_sym returns :controller. Symbol identifiers can be quoted and they can also contain special characters. Hence :”wow, this is a symbol!” is a valid symbol.
In short, symbols are used instead of strings wherever we care only about the identity and not the content. Why we use them? Because they are memory efficient and comparison operation on them are really fast.
Now if you are still confused about symbols, just forget about them. In time you will realize what they are!