&Blocks, &Procs, &Lambdas
Closures are technique for implementing lexical scoping.[1] They encapsulate functions, variables, and an environment. Blocks, Procs, and Lambdas are all examples of closures in Ruby.
Blocks
Blocks are chunks of code that respond to a yield
statement. You’ve definitely used Blocks before. Probably used one this morning. Most enumerator methods, like each
,map
, and reduce
, accept a block as an argument.
1 2 3 4 5 6 7 8 |
|
All the code between the do
and end
sandwich is a Block. Behind the scenes the each
enumerator method is using a yield
statement to pass the string into the Block we provided. If you’ve ever seen the error: no block given (yield) (LocalJumpError)
you’ve encountered a method that expected a block but did not receive it. A monkey-patched example reveals the internals of how methods that expect a Block work:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Everybody uses Blocks. They are fundamental building_blocks_ of Ruby programing.
Procs
Procs (short for “procedures”) are like Blocks with names. Formally, Procs are “anonymous functions” that can be represented as an object. Procs can be saved with a variable and reused throughout the program.[2] Unlike Blocks, Procs are actual objects constructed through use of the Proc
class.
1 2 3 |
|
However, Procs respond to .call
instead of yield
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Procs help your programs stay DRY. If you catch yourself using the same Block logic repeatedly within your application then store that logic in Proc to avoid repetition.
Lambdas
Lambdas are basically strict Procs with different return
behavior. Both Lambdas and Procs are instances of the Proc
class and both act like “anonymous functions”, however, Lambdas respect “arity” (a fancy way of saying that they will break if given an incorrect number of arguments, just like methods).
1 2 3 4 5 |
|
Alternatively, Lambdas can be created in what may be the most bad-ass name for obscure syntax — “stabby lambda”:
1 2 3 |
|
Lambdas and Procs also handle return
statements differently. Procs interpret the return
within the scope that called the proc. Lambdas, on the other hand, interpret the return
within the scope of the lambda (exactly the same way a method would handle a return
). This is might seem like an esoteric difference but can easily cause some problems.[3]
Ultimately, choosing between Lambdas and Procs really depends on preference. Both are perfect for encapsulating and storing code.