Bloques, Procs y Lambdas en Ruby

Alejandro Alvarez
Academia Hack
Published in
5 min readJun 6, 2019
Photo by Rick Mason on Unsplash

A todos nos ha parecido genial jugar con legos de pequeños, la capacidad de tomar pequeñas piezas y armar nuestra propia creación, lo que más me llama la atención es que, quitando o cambiando de lugar algunas piezas terminábamos con algo totalmente diferente.

En ruby tenemos algo muy similar, una función es como una pieza de lego y podemos juntar varias funciones para armar nuestra creación, por ejemplo:

Como vemos en el ejemplo, tenemos nuestra “creación”, una función llamada greet_and_ask que invoca a greet .

¿Que podríamos hacer para cambiar la pregunta?, en lugar de preguntar “¿cómo estás?”, que pregunte o que diga cualquier otra cosa.

Pues vayamos por partes, para cambiar la pregunta podríamos mover la linea 7 a funciones separadas, de esta forma podríamos crear varias funciones para preguntar o decir diferentes cosas.

Perfecto, esto hace el trabajo, siempre que queramos preguntar cosas diferentes pues creamos otra función aparte. Pero acá tenemos un problema, si tenemos muchas cosas diferentes que decir/preguntar se puede convertir bastante difícil llevar la cantidad y el orden de como se llama cada una de esas funciones.

¿Que tal si volvemos al comienzo donde teníamos pocas funciones pero mantener la capacidad de ejecutar diferentes funciones?, suena utópico, pero ¿es posible?.

Es aquí donde podemos hacer uso de bloques (blocks)

Photo by Kelly Sikkema on Unsplash

Bloque ¿que es?

Un bloque es un pedazo de código, una función anónima (sin nombre) que puede ser adherida a otra función, podemos verlo como una pieza de lego especial que puede encajar con cualquier otra pieza.

Se puede crear un bloque de dos formas, usando llaves {} o usando las keywords do end , es muy posible que en este punto ya hayas usado bloques sin saber que era, por ejemplo, al usar iteradores como each o times , le pasas o adhieres un bloque.

Los siguientes ejemplos son equivalentes.

Se puede escribir cualquier tipo de código ruby valido dentro de un bloque ya que simplemente es una función, solo que no posee un nombre.

Photo by Ben White on Unsplash

¡¡Espera!!, si no posee un nombre, entonces ¿como lo invoco?

Si tenemos una función (en nuestro caso greet_and_ask) y le pasamos un bloque, podemos invocar o ejecutar el bloque con la keyword yield .

yield ejecuta el bloque que se le pasa a una función.

De esta forma tenemos la posibilidad de ejecutar la misma función greet_and_ask y cambiar su comportamiento según el bloque que le pasemos.

¡AJA! ¿entonces los iteradores como each usan yield?

Bueno si usan yield pero van un poco mas allá, le pasan parámetros a el bloque, pasandole parámetros a yield.

Si le pasamos parámetros a yield este le pasa estos parámetros a el bloque, y la forma de obtener y usar los parámetros dentro de el bloque es con el pipe operator |param1, param2|

También podemos ejecutar varias veces yield lo que invoca el bloque la misma cantidad de veces.

Pasar más de un bloque a una función

No es posible con la sintaxis que usamos hasta ahora pasar más de un bloque a una función, sin embargo podemos hacer uso de otro concepto en ruby llamado proc .

Proc nos permite guardar un bloque sin ejecutar/invocar en una variable, para ejecutar un proc basta con llamar el método call sobre el proc.

call tiene un comportamiento similar a yield, también podemos pasar parámetros y este se los pasara al bloque

Con este concepto podemos pasar varios bloques, máximo uno como bloque y la cantidad que queramos como procs

Bloque implícito y explicito

Photo by Emily Morter on Unsplash

Por defecto los bloques que recibe una función son implícitos, se asume que se recibe el bloque y esta viviendo dentro de la función de forma casi transparente.

¿Como saber si recibiste un block?, el keyword block_given? nos da un valor booleano que representa si un bloque implícito fue pasado a la función.

Hay una forma de convertir un bloque recibido dentro de una función a un proc y tomarlo como un parámetro común con el keyword & seguido de el nombre del argumento.

Lambda

Un lambda es otra forma de guardar un bloque dentro de una variable o pasar un bloque por parámetro al igual que un proc .

Se puede crear un lambda de la siguiente forma

La diferencia de lambda y bloques además de la sintaxis, es que los lambdas son estrictos a la hora de la cantidad de parámetros que reciben, en otras palabras, un lambda genera un error al momento de ejecutar si no recibe la misma cantidad de parámetros con los que fue construido.

Un bloque no es estricto con la cantidad de parámetros que recibe, el siguiente ejemplo es código valido ruby

Mientras que un lambda genera error si intentamos lo mismo

En este artículo aprendimos un poco a entender como los bloques funcionan, que ya los estuvimos usando pero no lo sabíamos, bloques implícitos y explícitos, la diferencia entre un proc y un lambda en ruby.

Photo by Joshua Earle on Unsplash

Con estas bases podemos dominar por completo el lenguaje, ya que en ruby donde quiera que veas estará un bloque esperando a ser ejecutado.

¡Espero que hayas disfrutado el leer este artículo tanto como yo lo disfrute escribiéndolo!

--

--