Back-End

19 mai, 2015

Referências circulares no Ruby 2.2.x

Publicidade

Eu estava para escrever esse artigo faz algum tempo, desde que saiu a versão 2.2.0 da linguagem Ruby, mas nunca dava tempo… Até que, rodando um projeto nessa versão, me lembrei de um detalhe importante, já consertado em gems mais novas, mas que vale a pena alertar.

Vamos considerar o seguinte código:

class FooBar
  def foo
    "I'm in foo!"
  end
 
  def bar(foo = foo)
    puts foo
  end
end
 
foobar = FooBar.new
foobar.bar
foobar.bar("Not using foo!")

Podemos ver que temos dois métodos ali: foo, que retorna uma String, e bar, que utiliza um argumento com valor default, que no caso de não ter sido enviado, vai utilizar o retorno de foo. Rodando o código em uma versão menor que 2.2.x, é exibido o seguinte resultado:

<code>$ ruby circular.rb 
I'm in foo!
Not using foo!
</code>

Mas, rodando a partir da versão 2.2.0, temos o seguinte resultado:

<code>$ ruby circular.rb                                                                                                                                          
circular.rb:6: warning: circular argument reference - foo

Not using foo!
</code>

O que ocorre é que, a partir da versão 2.2.0, o argumento foo (à esquerda) está procurando uma variável foo (à direita), e como ela não existe e seria ali uma referência para a própria variável que está sendo criada na assinatura do método (daí a referência circular), é atribuído o valor de nil e disparado um warning.

Para utilizar o comportamento anterior nas versões a partir de 2.2.x, temos que fazer uma referência explícita ao método foo na linha 6, da seguinte maneira:

<code>  def bar(foo = foo())
</code>

Algumas gems do Rails, dependendo da versão, estavam com esse tipo de problema (como por exemplo, o ActiveSupport), mas aparentemente em versões atuais, já foi resolvido. Na hora que forem rodar seus projetos com versões novas do Ruby a partir das 2.2.x, fiquem espertos com isso.