Eustáquio Rangel

Desenvolvedor, pai, metalhead, ciclista

Símbolos em Ruby

Publicado em Developer


Recebi um email ontem comentando sobre a (curta) explicação de Símbolos que eu dou no meu tutorial de Ruby. Realmente é bem curta, e eu acho que esqueci o quanto o conceito de símbolos demorou para entrar na minha cabeça, talvez justamente por falta de alguma explicação mais clara para os newcomers de Ruby.

Vou tentar retificar meu erro aqui. Como digo na apostila, símbolos são como "strings levinhas". O que seria isso? Se vocês leram a apostila, sabem que Strings em Ruby alocam espaço na memória, ao contrário dos immediate values, (Fixnum's, booleanos, nulos e símbolos), que não alocam memória para os objetos.

Levando isso em conta, vamos imaginar assim: imagine seu programa cheio de Strings, todo programa usa um monte de Strings, mas que tal trocar essas Strings por símbolos onde você puder? Ia economizar um monte de memória, e o garbage collector agradece. Vou mostrar isso na prática, com um programinha besta que faz uma coisa besta mas que serve perfeitamente para o exemplo:

def azul?(s)
   return s=="azul"
end

puts "Há #{ObjectSpace.each_object(String){}} Strings na memória."
1000.times {
   azul?("verde")
}
puts "Agora há #{ObjectSpace.each_object(String){}} Strings na memória."

O que esse programa faz? Não muita coisa. Ele tem um método azul? (lembrem-se que métodos que tem ? no final são chamados de métodos predicados em Ruby), que verifica se o valor que passamos para ele é uma String "azul" ou não.

Executando esse programa, tenho:

[taq@~]ruby symbols.rb                                               
Há 168 Strings na memória.
Agora há 2170 Strings na memória.

Ouch. Criamos 2002 Strings (as 2000 do loop mais as 2 mensagens impressas). Se levarmos em conta que "verde" tem 5 bytes e "azul" tem 4 bytes, alocamos pouco mais de 8k na memória. Pouca coisa? É, mas quantas vezes esse código vai rodar e durante quanto tempo? É uma boa prática se preocupar com otimização desde códigos mais pequenos, simples e de curta duração, pois isso se reflete depois em código mais extensos, complexos e de longa duração. Questão de costume.

E como fazer otimização nesse código? Olhem os símbolos aí! Vamos alterar nosso programa para:

def azul?(s)
   return s==:azul
end

puts "Há #{ObjectSpace.each_object(String){}} Strings na memória."
1000.times {
   azul?(:verde)
}
puts "Agora há #{ObjectSpace.each_object(String){}} Strings na memória."

Executando esse programa, tenho:

[taq@~]ruby symbols.rb                                              
Há 166 Strings na memória.
Agora há 168 Strings na memória.

UAU! Economizei 2000 Strings! No programa só utilizei 2 símbolos, :verde (não é o Aurélio!) e :azul, que foram criados apenas uma vez durante todo o tempo de vida do programa. Isso mostra como o uso de símbolos é uma coisa a se pensar naqueles programas que usam várias Strings "identificáveis", vamos dizer assim, como no caso das cores, no exemplo.




Comentários

Comentários fechados.

Sem nenhum comentário.

Artigos anteriores