#5 Metaprogramação: Procs, lambdas e &

18 February 2010

Existem ainda diversas formas de se trabalhar com blocos em Ruby, métodos como instance_eval e instance_exec(este último apenas no Ruby 1.9) são formas de utilizá-los.

Com o passar do tempo objetos criados apenas para testar o comportamento de blocos foram criados, e a esses é dado o nome de Clean Rooms. Diversos frameworks se utilizam desses conceitos, como o RSpec, para citar um exemplo, no método should_receive.

Mas existe algo mais obscuro com relação a blocos. Blocos tem a característica de ser um conjuto de código a ser empacotado e chamado apenas depois, quando o programador julgar necessário.

Package code first, call it later
Existem 3 maneiras basicamente para se utilizar essa estratégia em Ruby. São elas:
  • 1) Proc que basicamente é um bloco convertido em objeto
  • 2) Lambda, que é uma pequena variação de uma proc
  • 3) em um método.




Proc
Blocos não são objetos, e isso é uma discussão longa na comunidade Ruby. Porém, imagine que você precisa guardar um bloco de código para executar depois. Você precisa de um objeto. Isso é uma Proc, um bloco que foi convertido em objeto. Para criar uma Proc basta passar o bloco para Proc.new e chamá-lo com call. Essa técnica é conhecida como Deferred Evaluation.

Existem ainda dois métodos do Kernel que convertem blocos para Procs: lambda() e proc().



O operador &
Um bloco é como um argumento adicional e anonimo passado a um método. Normalmente um bloco é chamado utilizando yield. Mas existem dois casos que isso não é suficiente:

  • Quando você precisa passar o bloco pra outro método.
  • Quando você quer converter o bloco para Proc.


Pra conseguir isso você precisa de alguma forma nomear o bloco. Pra isso você precisa de um argumento especial no seu método. Esse argumento deve ser o último e deve começar com o operador &.



Utilizando o operador &, podemos enviar o bloco (agora como Proc) para outro método ou mesmo retornar a Proc:



Ainda é possível fazer o contrário, ou seja, converter uma Proc para bloco com o operador &. Quando o método for chamado, o operador vai converter a Proc para bloco e passar para o método:



Procs x Lambdas
Ok..mas.. afinal..qual a diferença entre criar uma Proc através de proc() ou lambda() ?

Existem basicamente 2 diferenças entre procs e lambdas. A primeira tem a ver com a palavra return e a segunda com argumentos.

Return
A primeira diferenca entre proc() e lambda() está na palvra return.

Com lambda, return apenas retorna alguma informação do lambda. Com proc(), o return retorna do escopo onde a proc foi definida:



Argumentos
A segunda diferença entre proc() e lambda() está na forma com que os argumentos são checados.

Suponha que a Proc tenha sido criada precisando receber 2 parâmetros. Existe um método chamado arity para checar esse número. O que acontece caso seja passado apenas 1 ou 3 argumentos, ou seja, o número errado? No geral, lambda geraria um ArgumentError enquanto proc tentaria preencher da melhor forma possível:



Continua Próximo post - Definindo Classes
comments powered by Disqus