Blog

LISTAR TODOS OS POSTS - Assine os feeds dos posts e comentários

Métodos singleton no Ruby 1.9

Publicado/atualizado em 30/08/2007 10:19

Durante o percurso do curso (credo!) da segunda turma de Ruby eu percebi que algumas das "magias negras" da linguagem podem confundir (e talvez até assustar) quem está chegando agora. Apesar de eu tentar passar esse tipo de coisa de um jeito mais claro, realmente tem horas que fica meio complicado "externar" alguns dos conceitos que ocorrem nessas coisas que são diferenciais de Ruby em relação á algumas outras linguagens. Toda vez que eu vejo que não consegui passar o conceito claro de uma tacada só fico pensando em como revisar a didática e os códigos da aula para atingir isso.

Por exemplo, a "facilidade" de inserir um método em um objeto (não na classe), que pode ser feito assim:

 1 str1 = "oi"
 2 str2 = "hello"
 3 
 4 (class << str1; self; end;).class_eval do
 5    define_method(:foo) do
 6       puts "bar!"
 7    end
 8 end
 9 
10 str1.foo
11 str2.foo

Rodando isso vamos ter:

[taq@~]ruby singleton.rb
bar!
singleton.rb:11: undefined method `foo' for "hello":String (NoMethodError)

Até aí tudo bem, somente str1 que tem o método, mas o lance do (class << str1; self; end;) realmente assusta um pouco. Aí fui dar uma verificada no Ruby 1.9, que tem um método que facilita muito esse tipo de coisa e ... ué, cadê o mardito?

Fiquei até as tantas procurando o dito cujo no código do SVN, tanto no código em Ruby como no código em C, escovando bits e nada de achar. Aí chutei o balde e pedi ajuda, mandei uma mensagem para a lista de discussão perguntando onde foi que o método se enfiou. A primeira resposta foi que o método não estava definido, mas puxa, isso eu já sabia, pelo menos no código atual. Aí mencionei algumas URLs onde ele já havia sido comentado, inclusive na documentação do 1.9 e no Changelog, comentado pelo próprio Matz. Como alguma outra resposta estava demorando um pouquinho e eu estava bem curioso sobre o assunto, entrei em contato com o Mauricio Fernandez e perguntei se ele sabia de alguma coisa.

Ele me respondeu que realmente o código do método estava lá, mas foi perdido (acidentalmente ou não) durante o merge do YARV (que inclusive eu mencionei aqui). E hoje o Nobuyoshi Nakada me confirmou isso e indicou que já foi corrigido. Vejam a thread aqui.

E agora, senhoras e senhores, com vocês, o novo jeito de fazer o código acima, já no Ruby 1.9, com define_singleton_method:

1 str1 = "oi"
2 str2 = "hello"
3 
4 str1.define_singleton_method(:foo) { puts "bar!" }
5 
6 str1.foo
7 str2.foo

Rodando o bicho:

[taq@]ruby1.9 singleton2.rb
bar!
singleton2.rb:7:in `method_missing': undefined method `foo' for "hello":String
(NoMethodError)

Melhor de bom hein? E tem o fato que a performance do Ruby 1.9 está muito boa, tem casos aqui que eu vi que chega a ficar de 2 a 4 vezes mais rápida! Vou montar alguns benchmarks e publico o resultado aqui depois.

Atualizado: Dei uma olhada no Changelog da versão que peguei do SVN e aqui está o dito cujo, inclusive com um link para a minha mensagem na lista Ruby-talk:

Thu Aug 30 14:06:50 2007  Nobuyoshi Nakada  
* proc.c (rb_obj_define_method): reverted.  [ruby-talk:266637]

Aqui está o código que voltou:

1 /* Kernel */
2 rb_define_method(rb_mKernel, "define_singleton_method", rb_obj_define_method, -1);

Permalink: http://eustaquiorangel.com/posts/454

salvar no del.icio.ussalvar no diggsalvar no rec6 Veja o que estão dizendo sobre isso.

Comente

Linhas em branco viram saltos de linha. Se você quiser mostrar algum código, por favor use o pastebin e informe a URL.

*

*

Responda: Qual linguagem que tem um rubí­ como sí­mbolo?  
Clique aqui se não souber essa resposta!

* campos obrigatórios

Comentários

1 - Caio Moritz Ronchi disse em 30/08/2007 07:03

Olá, Taq, parabéns pelo post!

Eu também nunca fui fã desse (class << str1; self; end;), mas como eu nunca usei ele pra coisas muito úteis não me irritava tanto.

Essa nova maneira ficou realmente melhor (sempre que vejo um "eval", em qualquer linguagem, logo penso que foi uma gambiarra dos criadores, mesmo em Ruby).


2 - Lucious disse em 30/08/2007 15:32

Taq, eu me amarro em Ruby, ouvi falar há algum tempo e comecei a estudar, apesar de ter parado um pouco. Mas esse lance de definir métodos em objetos não diminui a segurança? Afinal posso definir um método que mexe em coisa que eu normalmente não poderia mexer, ou não é assim que funciona? Existe alguma restrição à o que pode ser feito com método "pós definido"?


3 - TaQ disse em 30/08/2007 16:43

Caio, obrigado! Realmente fica bem mais fácil assim, e por isso que eu corri atrás quando não vi o método no código ehehe. :-)

Lucious, com Ruby você pode mexer em muitas coisas e talvez "bagunçar o coreto" em algumas, como por exemplo, alterar algum método de alguma classe "base" para um comportamento não esperado, e pode dar um tiro no pé fácil, fácil fazendo isso. No caso acima, não há limitações no método inserido diferentes dos outros similares que já estavam definidos no objeto.

Eu particularmente vejo esse tipo de coisa como uma coisa boa e não como uma coisa ruim, pois se você souber o que está fazendo a linguagem te dá muitos recursos e muita flexibilidade. Do contrário ... bom, aí é melhor nem mexer. :-)


4 - Ronie Uliana disse em 31/08/2007 09:34

Tem esse post bem antigo do Why que explica bem legal essa coisa de metaclasses e como declarar métodos singleton. Inclusive, de cara ele já mostra alguns pequenos métodos utilitários para trabalhar com isso (que uso sempre que preciso).

http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Vale a pena dar uma checada


Anterior Próximo Últimos Índice