In Ruby I can write some things in two different ways:
I can do this:
What is the difference?
Short version : Use
:simbolos for code control
"strings" , and
"strings" for what will appear on the user's screen.
The first thing that must be said is that you must not confuse strings with symbols. When you write
:string , you are instanced a symbol. When you write
"string" are instanced a string. Let's see this in practice:
:string.class => Symbol 'string'.class => String
The methods that are available for
String objects are not the same as those available for
Symbol objects. So often these objects are not interchangeable.
The biggest difference between a symbol and a string is that a symbol is immutable . This means that once it's instanced, it's impossible to change its value. A string, on the other hand, is mutable. For example, it is possible to use the
tr! to change the value of a string:
a = 'string' => "string" a => "string" # valor da string a.tr!('i', 'e') => "streng" a => "streng" # mesma variável possui outro valor agora
One very important difference is that an object of the symbol class never has its memory deallocated, unlike a string. Ruby is an interpreted language that has a garbage collector – this means you don't have to manually allocate and deallocate memory as is necessary in lower-level languages like C (via the
malloc function, for example). When you no longer use a string, ruby's garbage collector discards that string. This never happens with symbols. To free the memory consumed by symbols, there is only one way: Exiting your program.
When a program consumes more and more memory without ever freeing it, that program is leaking memory . If you leave it running forever, the memory used will be increasing. This is not desirable for programs that will run for a long time, for example a Rails application. To avoid this, you should not dynamically create symbols in the program on unknown strings. For example, using the
to_sym method in user input.
Now that I'm scared, let's get to the good part about the symbols 🙂
Since they are immutable, it is not necessary to instance them each time they appear in the program. This means that ruby notices that there is already a symbol like that one, and uses it again, as many times as necessary. Let's prove it:
"minha string".object_id == "minha_string".object_id => false :simbolo.object_id == :simbolo.object_id => true
As you can see, the first line instantiates two different objects, while the second uses the same object twice. This proves that ruby reuses symbols but not strings.
Okay, cool. I dont care? The problem is that instance or compare strings takes much longer than instance or compare symbols. So, despite losing a little by constantly using more memory, operations done with symbols are usually faster.
As we have seen, a symbol comparison can be done with
object_id , while a string is done by comparing the internal value. This is much more expensive for the processor, which works at the bit level, where numbers are represented using much less space than strings.
I don't say you will compare a symbol manually. For example, using symbols as keys for a
Hash type object where values will be fetched often greatly improves performance, precisely because comparing symbols is faster than comparing strings.
Due to its characteristics, Symbols were designed to be used for code control. For example, for keys of a dictionary or a
tipo attribute of an object. You will constantly use these values in code, and they are used for comparison (direct in the attribute case, implicit in the key case for a hash). That's why it's more advantageous to use symbols and avoid instantiating a new string each time your code is used.
Strings, on the other hand, glow when values are manipulated, or when they are dynamically defined. For example, for the nickname of a user on a website – there are many users and hardly everyone will enter the site at the same time, so there is no reason to use a symbol and suffer from increased memory.