This is part 2 of a three-part series.
Part 1 covers the following four fundamentals:
- Definitions of Code Block, Proc, Lambda, and Closure
- Constructions
- Calling a Code Block/Proc/Lambda
- Passing and Returning Procs
Part 2, this post, covers
- Scopes, Universes, and Lunch Boxes [FUN STUFF]
- Differences between a Proc and a Lambda
Part 3 covers:
- Proc <> Code Block Conversion and Ampersand(&)
The most important takeaways from part 1 are the definitions:
- a
code block
is a block of code - a
proc
is an object that contains a code block - a
lambda
is a special type of proc - A
closure
is a function that: 1. can be passed around as a variable and 2. binds to the same scope in which it was created (more on that in this post).
To some extents, code blocks
, procs
, and lambdas
, can be seen as closures
.
Let’s jump right into the FUN!
Scopes, Universes, and Lunch Boxes
I like to think of a scope as a universe.
A code block
/proc
/lambda
/closure
preserves the local variable bindings that are in effect when it is created 1.
In other words, a code block
/proc
/lambda
/closure
is IN the universe that is in effect when it is created.
Let’s see it in action:

As we can see, the apple in the top level is reachable by both the proc and the code block.
A code block
/proc
/lambda
/closure
is not only in the universe that is in effect when it is created, it also can carry that universe with it.
We will talk more about the universe-carrying part in a second. Before that, let’s take a look at what happens when you create a class or a method.
When a class or a method is created, a new scope is created. They CREATE their own brand new universe.
Let’s see that in action as well:

The first time when we called the print_apple method, we got a NameError
. That was because the apple was not in the method’s scope: the method was in a different universe. In the method’s universe, there was no apple.
Later when we redefined the method and created an apple inside the method, we could see that the apple inside the method was not the same apple as the one outside of the method. Although they both called apple
, they are literary two different apples in two different universes.
Now, let’s go back to the idea of a code block
/proc
/lambda
/closure
carries its universe with it. We can see it in effect when two different universes come together — that’s when the fun begins!
I will let the code speaks for itself:

In the first two lines, a blue universe and a proc were defined. Inside the method, a red universe was defined. When we called passed_in_proc.call
, the code, { universe }
, held by the proc was executed, and the blue universe was returned.
You can think of the way a code block
/proc
/lambda
/closure
carries its universe with it the same way as you carry your lunch box with you to work. You put your meal and fruits inside your lunch box and take it with you. When you open it again at work, the meal and fruits are still there. Your office kitchen might have the same type of fruits, but they are not the same as the ones you take from home.
Differences between a proc and a lambda
Let’s revisit the definitions:
- a
proc
is an object that contains a code block - a
lambda
is a special type of proc
This is a metal picture you can have: procs
= regular procs
+ lambdas

Tony Tony Chopper is here b/c he is cute!
There are three differences between a regular proc and a lambda.
1. The ways they are constructed are different:
- a
regular proc
is constructed by eitherProc.new
orproc
- a
lambda
is constructed by eitherlambda
or->
(stabby lambda)
Proc.new { puts 'I am a proc' } proc { puts 'I am a proc' } lambda { puts 'I am a lambda' } -> { puts 'I am a lambda' }
2. The ways they return are different:
- a
lambda
return from the code block it contains - a
proc
return from the scope that calls it
The code speaks clear and loud:

An excellent example from The Well-Grounded Rubyist
3. A lambda
needs to be called with the exact number of arguments, where a proc
is more loose about the arguments it receives.

Woohoo, that’s all I got for today. We have learned about scopes, universes, lunch boxes, and the difference between procs and lambdas.
Next up is the grand finale of the series where we will take an in-depth look at the use of the ampersand (&
) to convert procs
and code blocks
. It will be the most challenging and most fun part of the series. It’s something you don’t want to miss.
[1]: Definition from The Well-Grounded Rubyist.
Really a good post. I got something new from the post. Thanks.
Well explained. Thank you
There is a typo in “Differences between a proc and a lambda” section.
Should be
proc { puts ‘I am a proc’ }
Thanks, Andrew!