#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