Pssssssss. Youse wanna try a code block? Everybody's doing it.
Just kidding. You've been using code blocks. That's right: you're already a user. Everytime you've iterated over an Array or Hash with each
, everytime you've transformed an Array or Hash with map
, everytime you've used an Enumerable, you have likely passed in your own code block. You're a code blockhead, Charlie Brown.
A code block comes between two forms:
- curly braces: { }
- do... end
How do I know which form to use? The convention is if your code block is a single line, then use curly braces; if it's more, use do... end. Here's an example of two equivalent code blocks in each style:
You may have spent a few sleepless nights wondering: What auto-magically stuffs my code block variables-- num
, in this case-- with values from the collection? Well lose sleep no longer for the mechanism behind it is: yield
. In fact, using this mechanism, we can roll our own Array#each. Let's call ours Array#my_each (see below). Notice that the method iterates through the array as we knew something had to. And for each element, it calls yield
, yielding control over to your code block, and passing parameters-- the Array element, in this case-- that fills the variables in your code block. Mystery solved! Sweet dreams.
Fun fact: not everything in Ruby is an object. Heresy! Code blocks are actually one of those exceptions. Code blocks are not objects! I don't know what to believe in anymore. And because it's not an object, we can't save a code block to a variable. Oy vey! What if I have redundant code blocks in my code? How do I stay D.R.Y.??
Enter: Procs and lambdas.
Let's start with Procs. Proc is short for Procedure. Unlike code blocks, procs are objects. Thus, we can save a proc to a variable. So we can think of a proc as a "saved" code block. Below, we create a Proc with the same code block as previously seen and assign it to the variable add_one_proc
:
What's the deal with that ampersand sign? Oh that. We already know from experience that methods like .each, .map, and similar get passed a code block. &
is used to convert a proc into a code block. That's it.
Circling back to lambdas: lambdas are objects and can be thought of as "saved" code blocks as well. Below is an equivalent code block to the previous examples, except we're creating a lambda this time:
As you can see, lambdas are very similar to procs. In fact, lambdas are in reality Proc objects themselves! There are some key differences though. I won't go into the specifics myself (see the Notes section below, as well as the References links). But a useful way of thinking about them: a lambda is like an anonymous method-- it behaves like methods typically behave when called; procs on the other hand, are like pasted code snippets-- as if you pasted the code block directly into the method enclosing the proc.
Notes:
1) A block is just a bit of code between do..end or {}. It's not an object on its own, but it can be passed to methods like .each or .select.
2) A proc is a saved block we can use over and over. (short for Procedure)
3) A lambda is just like a proc, only it cares about the number of arguments it gets and it returns to its calling method rather than returning immediately.
Src: http://www.codecademy.com/courses/ruby-beginner-en-L3ZCI/2/5
Differences between Blocks and Procs
1. Procs are objects, blocks are not
2. At most one block can apear in an argument list
Differences between Procs and Lambdas
1. Lambdas check the number of arguments, while procs do not
2. Lambdas and procs treat the ‘return’ keyword differently
Src: http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/
A lambda gives you more flexibility with what it returns (like if you want to return multiple values at once) because you can safely use the explicit return statement inside of one. With lambdas, return will only return from the lambda itself and not the enclosing method, which is what happens if you use return inside a block or Proc.
Lambdas are also much stricter than Procs about you passing them the correct number of arguments (you'll get an error if you pass the wrong number).
Src: http://www.eriktrautman.com/posts/ruby-explained-blocks-procs-and-lambdas-aka-closures
References:
- What Is the Difference Between a Block, a Proc, and a Lambda in Ruby?, Adam Waxman
- Understanding Ruby Blocks, Procs and Lambdas, Reactive.IO
- Ruby Explained: Blocks, Procs, and Lambdas, aka "Closures", Erik Trautman
- Blocks, Procs, & Lambdas, Codecademy
- Blocks, Procs, and Lambdas, RubyMonk