Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use symbols instead of strings in Ruby?

Tags:

symbols

ruby

If there are at least two instances of the same string in my script, should I instead use a symbol?

like image 231
Alan Coromano Avatar asked May 18 '13 05:05

Alan Coromano


People also ask

What is the difference between symbol and string in Ruby?

There are two main differences between String and Symbol in Ruby. String is mutable and Symbol is not: Because the String is mutable, it can be change in somewhere and can lead to the result is not correct. Symbol is immutable.

What is a valid difference between strings and symbols in Ruby on Rails?

While symbols and strings give you the same results when used as keys in hashes, they are not the same thing. A symbol is immutable while a string is mutable. You can't change a symbol once it's created. :locked on different lines in your code is the same object.

When should you use a symbol to store text and when should you use a string Ruby?

One rule of thumb is that if the text at hand is “data”, then use a string. If it's code, then use a symbol, especially when used as keys in hashes (see below). Another way of looking at symbols is that they aren't really text, even though they read well. Instead they are unique identifiers, like numbers, or bar codes.

Why is it not a good idea to dynamically create a lot of symbols?

If you dynamically create lots of symbols, you are allocating a lot of memory that can't be freed until your program ends. You should only dynamically create symbols (using string.


2 Answers

TL;DR

A simple rule of thumb is to use symbols every time you need internal identifiers. For Ruby < 2.2 only use symbols when they aren't generated dynamically, to avoid memory leaks.

Full answer

The only reason not to use them for identifiers that are generated dynamically is because of memory concerns.

This question is very common because many programming languages don't have symbols, only strings, and thus strings are also used as identifiers in your code. You should be worrying about what symbols are meant to be, not only when you should use symbols. Symbols are meant to be identifiers. If you follow this philosophy, chances are that you will do things right.

There are several differences between the implementation of symbols and strings. The most important thing about symbols is that they are immutable. This means that they will never have their value changed. Because of this, symbols are instantiated faster than strings and some operations like comparing two symbols is also faster.

The fact that a symbol is immutable allows Ruby to use the same object every time you reference the symbol, saving memory. So every time the interpreter reads :my_key it can take it from memory instead of instantiate it again. This is less expensive than initializing a new string every time.

You can get a list all symbols that are already instantiated with the command Symbol.all_symbols:

symbols_count = Symbol.all_symbols.count # all_symbols is an array with all                                           # instantiated symbols.  a = :one puts a.object_id # prints 167778   a = :two puts a.object_id # prints 167858  a = :one puts a.object_id # prints 167778 again - the same object_id from the first time!  puts Symbol.all_symbols.count - symbols_count # prints 2, the two objects we created. 

For Ruby versions before 2.2, once a symbol is instantiated, this memory will never be free again. The only way to free the memory is restarting the application. So symbols are also a major cause of memory leaks when used incorrectly. The simplest way to generate a memory leak is using the method to_sym on user input data, since this data will always change, a new portion of the memory will be used forever in the software instance. Ruby 2.2 introduced the symbol garbage collector, which frees symbols generated dynamically, so the memory leaks generated by creating symbols dynamically it is not a concern any longer.

Answering your question:

Is it true I have to use a symbol instead of a string if there is at least two the same strings in my application or script?

If what you are looking for is an identifier to be used internally at your code, you should be using symbols. If you are printing output, you should go with strings, even if it appears more than once, even allocating two different objects in memory.

Here's the reasoning:

  1. Printing the symbols will be slower than printing strings because they are cast to strings.
  2. Having lots of different symbols will increase the overall memory usage of your application since they are never deallocated. And you are never using all strings from your code at the same time.

Use case by @AlanDert

@AlanDert: if I use many times something like %input{type: :checkbox} in haml code, what should I use as checkbox?

Me: Yes.

@AlanDert: But to print out a symbol on html page, it should be converted to string, shouldn't it? what's the point of using it then?

What is the type of an input? An identifier of the type of input you want to use or something you want to show to the user?

It is true that it will become HTML code at some point, but at the moment you are writing that line of your code, it is mean to be an identifier - it identifies what kind of input field you need. Thus, it is used over and over again in your code, and have always the same "string" of characters as the identifier and won't generate a memory leak.

That said, why don't we evaluate the data to see if strings are faster?

This is a simple benchmark I created for this:

require 'benchmark' require 'haml'  str = Benchmark.measure do   10_000.times do     Haml::Engine.new('%input{type: "checkbox"}').render   end end.total  sym = Benchmark.measure do   10_000.times do     Haml::Engine.new('%input{type: :checkbox}').render   end end.total  puts "String: " + str.to_s puts "Symbol: " + sym.to_s 

Three outputs:

# first time String: 5.14 Symbol: 5.07 #second String: 5.29 Symbol: 5.050000000000001 #third String: 4.7700000000000005 Symbol: 4.68 

So using smbols is actually a bit faster than using strings. Why is that? It depends on the way HAML is implemented. I would need to hack a bit on HAML code to see, but if you keep using symbols in the concept of an identifier, your application will be faster and reliable. When questions strike, benchmark it and get your answers.

like image 86
fotanus Avatar answered Oct 19 '22 05:10

fotanus


Put simply, a symbol is a name, composed of characters, but immutable. A string, on the contrary, is an ordered container for characters, whose contents are allowed to change.

like image 23
Boris Stitnicky Avatar answered Oct 19 '22 05:10

Boris Stitnicky