“AkitaOnRails” On Ruby Symbols

by Satish Talim on November 26, 2007

RubyLearning recently caught with Fabio Akita from Brazil and got his viewpoint on one of the vexing areas for beginners in Ruby – Symbols.

Fabio AkitaFabio Akita is a Brazilian Rails enthusiast, also known online as “AkitaOnRails”. He regularly write posts on his own blog and had published the very first book tailored for the Brazilian audience called “Repensando a Web com Rails”. He is now a full-time Ruby on Rails developer working as Brazil Rails Practice Manager for the Utah company Surgeworks LLC.

Ruby is very similar to many other object oriented languages. You can find similar constructs from non-dynamic languages as Java or C#. On the other hand, to start grasping all the possibilities of Ruby one has to invest some time learning what we call ‘Rubyisms’. One example is something called a *symbol*.

This is more obvious when you start learning Ruby through Rails. Much of Rails power comes from the fact that it uses a lot of rubyisms. Let’s see one example: (Note: You may want to brush up on Symbols and ActiveRecord before going through the examples that follow.)

class Transact < ActiveRecord::Base
  validates_presence_of :when
  validates_presence_of :category, :account
  validates_presence_of :value
  validates_numericality_of :value

  belongs_to :category
  belongs_to :account
end

‘class’ we understand, after all, the mainstream languages are ‘object-oriented’. But what are all those colons doing through all the code? Those denote Symbols. More important, the colons represent initializers of the class Symbol.

This can be quite confusing considering that the normal way of initializing an object is:

Symbol.new

The ‘new‘ call asks for the standard ‘initialize‘ method defined within the class. Turns out that this method is private, the idea being that all symbols should be instantiated with the colon notation.

Symbols are used as identifiers. Some other languages could simply use Strings instead of Symbols. In Ruby, it would become something like this:

class Transact < ActiveRecord::Base
  validates_presence_of "when"
  validates_presence_of "category", "account"
  validates_presence_of "value"
  validates_numericality_of "value"

  belongs_to "category"
  belongs_to "account"
end

Not so visually different: we got rid of the colons and went back to the comfortable quotation marks. They look the same but behave differently. Like Symbols in Ruby, Strings also have a special constructor. Instead of doing:

String.new("category")

We just do:

"category"

One could call these kind of shortcuts as “eye-candy”, but the languages would be pretty harsh without them. We use Strings all the time, and it would be extremely painful to instantiate new Strings without this special constructor: simply writing it between quotation marks.

The problem is, as Strings are easy to write, we overuse them more often than not. There is an important side-effect: each new construct instantiates a brand new object in memory, even though they have the same content. For instance:

>> "category".object_id
=> 2953810

>> "category".object_id
=> 2951340

Here, we instantiate two strings with the same content. Each object in memory has a unique ID so each string created above uses a separate memory slot and have separate IDs. Now imagine that the same string shows up in hundreds of different places throughout your project. You’re definitely using more memory than necessary.

But, this is not a new problem. For that, we have another construct in most languages called ‘constants’, Ruby included. We have to conscientiously plan and pre-define several constants beforehand. So, that’s how our previous example would be using memory efficient constants:

class Transact < ActiveRecord::Base
  ACCOUNT = "account"
  CATEGORY = "category"
  VALUE = "value"
  WHEN = "when"

  validates_presence_of WHEN
  validates_presence_of CATEGORY, ACCOUNT
  validates_presence_of VALUE
  validates_numericality_of VALUE

  belongs_to CATEGORY
  belongs_to ACCOUNT
end

This works, but this is not nearly as nice. First of all, you have to pre-define everything beforehand, either in the same class or a separated module just for constants. Second, the code is less elegant, less readable, thus, less maintainable.

So, we get back to the purpose of Symbols: being as memory efficient as constants but as easy to the eyes as full fledged strings. Quotation mark notation is already taken for Strings, capitalized words for constants, dollar sign for global variables and so on. So, colon was a good candidate.

Let’s see what it all means:

>> "string".object_id
=> 3001850
>> "string".object_id
=> 2999540

>> :string.object_id
=> 69618
>> :string.object_id
=> 69618

As we explained before, the first two strings have the same content and look similar, but they do occupy different memory slots, allowing for unnecessary duplication.

The last two symbols both are exactly the same thing. So I can call identifiers as symbols through all my code without worrying about duplication in memory. They are easy to initialize and easy to manage.

We can also transform a String into a Symbol and vice-versa:

>> "string".to_sym
=> :string
>> :symbol.to_s
=> "symbol"

One good place where this is put to good use is within Rails’ ActiveSupport. This package was made to extend the Ruby language, and one such extension was made to the ubiquitous Hash class. Let’s see an example:

>> params = { "id" => 1, "action" => "show" }
=> {"action"=>"show", "id"=>1}

>> params["id"]
=> 1

>> params.symbolize_keys!
=> {:id=>1, :action=>"show"}

>> params[:id]
=> 1

The first statement instantiates and populates a Hash (yet another special initialization notation). The second statement asks for the value identified by the key “id”, which is a string.

Instead of doing it this way, we can call the symbolize_keys! to transform all string keys into symbol keys. Now in the last statement we can use the more usual Rails notation as symbol keys within a Hash. When Rails receives a HTML Form post request, it only gets strings, so it is its job to convert everything into meaningful Rails objects. If you’ve been in the Rails world, you already saw this usage with controllers.

So, this is all to be said about Symbols: very simple constructs that makes code more readable and more efficient at the same time, which is compatible with the Ruby Way.

Thank you Fabio for showing us a different perspective on Symbols. In case you have any queries, questions on this article, kindly post your questions here and Fabio would be glad to answer.

Technorati Tags: , , ,

Posted by Satish Talim

{ 14 comments… read them below or add one }

enlightened November 29, 2007 at 10:55 pm

Thank you! This helped me very much. Very well written and clear!

Reply

Robert Crocker February 11, 2008 at 9:05 am

I’ve been trying to learn ROR for the last year or so and symbols have been a big stumbling block.

This is definitely the best explanation of the concept I’ve seen so far.

Reply

kenlistian March 26, 2008 at 2:22 pm

How do paramters for method to use symbol ?
Can do it?

#if sym_Paramter is symbol ,but i need convert
# it block ,how do?

def mymethod(:sym_Paramter)

end

Reply

Alex Kessaris August 4, 2008 at 6:43 am

Thank you very much! This tutorial was exactly what I needed to fully understand the basic idea behind symbols!

I was led here by Mr. Satish Talim’s excellent resource on learning Ruby, and I can see that it was an excellent referral to an invaluable resource!

Reply

Douglas January 13, 2009 at 12:38 am

#I followed this code with irb. One thing to mention,
require ‘ActiveSupport’

#to get
params.symbolize_keys!
#to return without a nil object.

#Thanks for the lesson.

Reply

Luiz Gustavo March 19, 2009 at 2:02 am

Nunca foi tão fácil entender um novo conceito!
Parabéns Fábio!
Obrigado Satish!

It has never been so easy to understand a new concept!
Congratulations Fabio!
Thanks Satish!

Reply

Viz April 30, 2009 at 6:16 am

Echoing what’s been said above – best explanation of symbols i’ve seen.

Reply

Hirak May 18, 2009 at 11:07 pm

excellent explanation….
*thanks Fabio*
*thanks Satish*

Reply

Rainer October 5, 2009 at 1:14 pm

I have used symbols since first being introduced to Ruby via RoR. They have always been somewhat mysterious to me. This explanation removes a lot of that mystery.
Thanks

Reply

rahul December 22, 2010 at 6:38 pm

The concept was presented in clear words and precise text.
I have a question here, in the rails world, there are many symbols that are being used. As a first time learner, how do i know which symbols are available?

Reply

Nicholaus Hughes May 10, 2011 at 5:43 am

Awesome. Clear and Concise.

I appreciate a simple explanation about something that doesn’t need to be complicated.

Reply

koteswara rao August 13, 2011 at 6:20 pm

Hi sir,i’m koti.i just came to know ruby.You explained well.But there is a little bit confusion to use symbols.You said that we can use symbols instead of strings.But i saw so many methods using symbol like this
before_filter :add_to_numbers
actually here add_to_numbers is a method but the method added with colon(:).so if we add colon to method,then what is meaning of that method included with colon?
could you clarify my doubt please

Reply

Abdul Basit October 19, 2011 at 4:18 pm

Hi Koti,
the methods like before_filter accepts parameter in string format(as symbols are special type of string)

Using eval() method, it is possible to execute the methods, by giving the method name as a string.

eval() can also be used to execute ActiveRecord methods.

eg,

model_name = “user”
method_name = “find_by_name”
eval(model_name.capitalize + ‘.’ + method_name +’ India’) # this is same as Country.find_by_name(‘India’)
—————————————

The explanation is not for, how before_filter is doing this. But this is one way for doing the same.

Reply

Jesse Ocon November 5, 2012 at 8:05 pm

Great explanation. This is definitely the best explanation of symbols that I have come across.

Reply

Leave a Comment

{ 7 trackbacks }

Previous post:

Next post: