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

Posted on February 18, 2010

5


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:

  • Proc, que basicamente é um bloco convertido em objeto
  • Lambda, que é uma pequena variação de uma proc
  • 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