Ruby: Diferença entre string e símbolo
Tags: ruby, rails, begginers, webdev
Published: 2021-11-24 16:28:03

Minha primeira dificuldade quando comecei a trabalhar com Ruby (on Rails) foi entender o que era aquele monte de `:` nos códigos, literalmente em todos os cantos. Mais difícil ainda foi entender as explicações nos primeiros resultados da busca "difference between string and symbols". Segui um bom tempo desenvolvendo código em Ruby sem ter entendido completamente a diferença entre essas duas classes, até que uma vez me deparei com um bug que foi causado por uma má decisão entre símbolo e string!

## Ponto de partida

Vamos discutir ao longo do post os seguintes casos:

1. Guardar dados
2. Representar algum valor (do seu programa)

Com "guardar dados" sendo o caso de uso de strings, como por exemplo, registrar o nome de um livro.

```ruby
titulo = 'O senhor dos anéis'
```
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 


> E o segundo caso: como assim representar um valor?

O uso dos símbolos são otimizados quando precisamos **representar** um valor que existe em nosso programa, como em uma associação do ActiveRecord:

`has_one :book`

ou em key de uma Hash (note também o uso da string para guardar um dado):

```ruby
hash = { name: "Vinicius" }
hash[:name]
=> "Vinicius"
```
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 
> Certo, mas por que símbolos são ***otimizados*** pra esse papel de "Representar um valor"?

Dois motivos!

O primeiro é que ***só pode haver uma instância de um símbolo***. O que isso quer dizer é que se eu mencionar o símbolo `:name` duas vezes no mesmo código, vai ser sempre o mesmo `:name`.

Por exemplo, se eu fizer:
```ruby
a = :teste
b = a
c = :teste
```

Eu terei certeza que `a`, `b` e `c` se referem ao mesmo objeto. Além disso, a velocidade de comparação entre símbolos é extremamente rápida!

```ruby
a == c # true
a === c # true
a.eql?(c) # true
a.equal?(c) # true
```
&nbsp;
O que não acontece com strings, já que toda vez que você atribui o valor "teste" para novas variáveis, novas strings são criadas (ocupando memória extra do seu programa).

O segundo motivo é que ***símbolos são imutáveis***. Não é possível alterar um símbolo como você faria com uma string: métodos como `upcase!` ou `capitalize!` não alteram o modificam. Benefício? Você tem a garantia que não terá uma parte do seu software modificando um símbolo *por acidente* (o que gera bugs difíceis de serem encontrados!).

## Conclusão

Quando você precisa de todo o arsenal de métodos como o `upcase`, `split`, ou outros, e o principal motivo é o de guardar um dado, seja um nome, data, etc, utilize uma string! 
Já quando o motivo é ***representar algo em seu código***, como o nome de um método, ou o um valor dentro de uma Hash, utilize símbolos.

Ainda confuso? Não se preocupe! Use o método `public_methods` em uma versão pré-1.9 do Ruby e veja que até programadores experientes ainda se confundem as vezes em qual escolher. Como esse método retorna todos os métodos (públicos) de um objeto, você há de concordar que o correto seria `public_methods` retornar uma array de símbolos, certo? Pois é, e nessas versões, se você fizesse:

```ruby
x = Object.new
puts x.public_methods
```
Você teria na verdade uma array de strings!

```ruby
["inspect",
"pretty_print_cycle",
"pretty_print_inspect",
"clone",
...
]
```
&nbsp;&nbsp;
Fonte: *OLSEN, Russen. Eloquent Ruby*