---
title: 'Procs and Lambdas'
source: 'https://academia.sh/en/courses/ruby-fundamentals/procs-and-lambdas'
course: 'Ruby Fundamentals'
language: en
updated: '2026-10-21T05:03:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Assigns a block to a variable as a proc or a lambda and calls it with call'
    - 'Measures the argument-checking difference between a proc and a lambda'
    - 'Asks what kind of object something is with lambda?'
    - 'Measures that the owner of the call method is the same for both kinds'
---

# Procs and Lambdas

For procs and lambdas, the two ways of turning a block into an object, a class is measured answering the call message, and the difference is shown to lie in argument checking and in the lambda? state.

In the previous two lessons a block was only a piece of code accompanying a method call: it stayed where it was written and could not be stored directly in a variable. A **proc** turns the block into an object; a **lambda** is a stricter form of the same object. Both have the class `Proc`. A proc carries the variables of the scope where it was defined; M01/K02 called this property a **closure**, and it is not redefined here.

This lesson's responder is the **class**: the `Proc` class answers the `call` message. The difference lies not in the class but in the object's **`lambda?` state**.

## Three Ways to Call

A lambda is written with `->`. To call it you use `call`, the dot-parenthesis shorthand `.()`, or square brackets; the three are the same message. The core classifies this call: if the owner of `call` is a `Class`, the responder is a **class**.

```ruby
# reply.rb — helpers that classify who answers a message

# Classification asks in order: is the expression a message at all (defined?),
# then do two different blocks give two different results, then who owns the method.
def responder(definition, owner: nil, result: nil, with_blocks: nil)
  return ["syntax", "defined? #{definition}"] unless definition == "method"

  if with_blocks
    first, second = with_blocks.call
    return ["block", "#{first.inspect} / #{second.inspect}"] unless first == second
  end

  kind = owner.instance_of?(Class) ? "class" : "module"
  [kind, "#{owner}, result #{result.inspect}"]
end
```

```ruby
# lambda.rb — who answers the lambda call
require_relative "reply"

double = ->(n) { n * 2 }
owner = double.method(:call).owner
kind, evidence = responder(defined?(double.call(3)), owner: owner, result: double.call(3))
puts "#{kind}  #{evidence}"
puts double.class
puts double.call(3)
puts double.(3)
puts double[3]
```
```
class  Proc, result 6
Proc
6
6
6
```

The first line is the core's `lambda call` observation: the **responder** is a **class**, and the owner is `Proc`. All three call forms gave `6`. **CB11.** The three forms were measured with the same result in this lesson; which one is preferred is a matter of writing style and is not measured.

## The Difference Between a Proc and a Lambda

The difference is not visible at first glance: both are called and both return a value. The distinction appears in argument checking. A lambda expects exactly the right number of arguments; a proc ignores the extra ones and fills in the missing ones with `nil`. In the error case, the class of the exception the lambda raises is printed, not its message.

```ruby
# difference.rb — the argument difference between a proc and a lambda
loose = proc { |x| x }
strict = lambda { |x| x }
puts loose.call(1, 2)

result = begin
  strict.call(1, 2)
rescue ArgumentError => error
  error.class
end
puts result

pair = proc { |x, y| [x, y] }
puts pair.call(1).inspect
puts "loose=#{loose.lambda?} strict=#{strict.lambda?}"
```
```
1
ArgumentError
[1, nil]
loose=false strict=true
```

When given two arguments at once, the proc dropped the extra one and returned `1`; the lambda raised `ArgumentError` on the same call. When the two-parameter proc was given a single argument, the missing parameter became `nil`. `lambda?` tells the two apart: `false` for the proc, `true` for the lambda.

## Procs from Other Objects

In Ruby, a proc can be obtained from other sources too: `to_proc` from a method object and `to_proc` from a symbol. Both behave like a lambda.

```ruby
# conversion.rb — a method and a symbol turn into a proc
def square(n)
  n * n
end

puts method(:square).to_proc.lambda?
puts :upcase.to_proc.lambda?
puts :upcase.to_proc.call("a")
```
```
true
true
A
```

The procs obtained from a method and from a symbol have a `lambda?` value of `true`. `:upcase.to_proc.call("a")` gave the uppercase string. This is the mechanism behind the `select(&:even?)` form seen in the previous lesson: `&` turns the symbol into a proc and passes it in place of the block.

## Carrying a Variable

A proc stays bound to the variables of the scope where it was defined. To see this, a method returns a lambda, and the lambda keeps incrementing the variable even after the method has finished.

```ruby
# counter.rb — a lambda carries the variable from where it was defined
def make_counter
  total = 0
  -> { total += 1 }
end

first = make_counter
second = make_counter
puts first.call
puts first.call
puts second.call
puts first.call
```
```
1
2
1
3
```

Each `make_counter` call set up its own `total` variable. `first` gave `1`, `2` and `3` in turn; `second` gave `1` from its own counter. The method had finished, but the lambda kept carrying the variable. **CB13.** This measurement shows two independent counters; two lambdas sharing the same variable are not measured in this lesson.

## Passing an Object in Place of a Block

A proc or a lambda can be passed to a method as a block by putting `&` in front of it. This joins `map` from the Blocks lesson with this lesson's objects. `arity`, for its part, gives as a number how many parameters the object expects.

```ruby
# as_block.rb — passing an object as a block, and arity
double = ->(n) { n * 2 }
loose = proc { |x, y| [x, y] }
puts [1, 2, 3].map(&double).inspect
puts "arity lambda=#{double.arity} proc=#{loose.arity}"
puts [[1, 2], [3, 4]].map(&loose).inspect
```
```
[2, 4, 6]
arity lambda=1 proc=2
[[1, 2], [3, 4]]
```

`map(&double)` handed each element to the lambda and collected `[2, 4, 6]`: there was no need to write a separate block. `arity` returned `1` for the lambda and `2` for the two-parameter proc. On the nested arrays, the proc split each inner array into two parameters and rebuilt the `[x, y]` array, so the result looked the same as the input. **CB14.** In this measurement the lambda was always called with a single element; what happens when a nested array is passed to a lambda with `&` was not measured.

## Where return Returns To

Another difference between a proc and a lambda is where `return` goes. The two methods below do the same job: they build an object inside, call it, and then try to return `2`.

```ruby
# return_difference.rb — return inside a proc and a lambda
def with_proc
  pr = proc { return 1 }
  pr.call
  2
end

def with_lambda
  l = lambda { return 1 }
  l.call
  2
end

puts with_proc
puts with_lambda
```
```
1
2
```

`with_proc` returned `1`: the `return` inside the proc ended not the proc but the method enclosing it, and the line with `2` was never reached. `with_lambda` returned `2`: the `return` inside the lambda ended only the lambda, and the method carried on from where it was. **CB30.** The measurement was made only inside a method; a `return` inside a proc at the top level was not tried in this lesson.

## Partial Application

`curry` turns a multi-parameter lambda into a chain that takes one parameter per call. When some of the parameters are given, a new object that waits for the rest is returned.

```ruby
# curry.rb — calling parameter by parameter with curry
add = ->(a, b, c) { a + b + c }
puts add.curry[1][2][3]
puts add.curry.(1, 2).(3)
partial = add.curry[1]
puts partial.class
puts partial.lambda?
```
```
6
6
Proc
true
```

With three square-bracket calls and with the `(1, 2).(3)` form, `curry` gave the same result, `6`. `add.curry[1]` returned a `Proc`, and this object was still a lambda. **CB31.** `curry` was measured only with a lambda of fixed parameters.

## The Method Object

`method(:name)` turns a method into an object. This object can be called, its owner can be asked, and it can be turned into a block with `&`.

```ruby
# method_object.rb — a Method object and to_proc with method
def square(n) = n * n
m = method(:square)
puts m.class
puts m.call(4)
puts "owner=#{m.owner} arity=#{m.arity}"
puts [1, 2, 3].map(&m).inspect
puts m.to_proc.class
```
```
Method
16
owner=Object arity=1
[1, 4, 9]
Proc
```

`method(:square)` gave a `Method` object and `call(4)` returned `16`. The owner of `square`, defined at the top level, was printed as `Object`. `map(&m)` passed the method in place of a block and produced `[1, 4, 9]`; `to_proc` returned a `Proc`. **CB32.** The measurement was made only with a method defined at the top level.

## Converting Between a Block and a Proc

If a method's last parameter is `&block`, the block given to it is turned into a `Proc` object. Conversely, a lambda can be passed in place of a block with `&`. The measurement below looks at whether the object's identity is preserved in these two directions.

```ruby
# block_proc.rb — conversion between a block and a lambda
def take(&block) = block
b = take { |x| x + 1 }
puts b.class
puts b.lambda?
puts b.call(1)
l = ->(x) { x + 1 }
puts take(&l).equal?(l)
puts take(&l).lambda?
```
```
Proc
false
2
true
true
```

The object that came back from the block was a `Proc`, and `lambda?` gave `false`. When a lambda was passed with `&l`, `take` returned the same object: `equal?` was `true` and `lambda?` was still `true`. So `&` did not turn a lambda into a proc. **CB33.** The measurement was made only with a single-parameter block and one lambda.

## Composing Callable Objects

`>>` and `<<` combine two callable objects into a single `Proc`. `f >> g` applies `f` first and then `g`; `f << g` does the reverse. A `Method` object can take part in the same composition.

```ruby
# compose.rb — composing procs
inc = ->(x) { x + 1 }
dbl = ->(x) { x * 2 }
puts (inc >> dbl).call(3)
puts (inc << dbl).call(3)
puts (inc >> dbl).class
puts (method(:Integer) >> inc).call("4")
```
```
8
7
Proc
5
```

`(inc >> dbl).call(3)` applied `inc` first and then `dbl`: `(3 + 1) * 2 = 8`. `(inc << dbl).call(3)` reversed the order: `inc(dbl(3)) = 7`. The result of the composition was a `Proc`. `method(:Integer) >> inc` composed a `Method` object with a lambda: `"4"` first became `4`, then gave `5`. **CB45.** The measurement was made with single-parameter lambdas.

## arity and parameters

`arity` reports how many parameters a callable object expects, and `parameters` reports the kind of each. A proc and a lambda can report the same parameter list differently.

```ruby
# arity.rb — arity and parameters
puts proc { |a, b| }.arity
puts lambda { |a, b| }.arity
puts proc { |*a| }.arity
puts lambda { |a, b = 1| }.arity
puts lambda { |a, b = 1| }.parameters.inspect
puts proc { |a, b| }.parameters.inspect
```
```
2
2
-1
-2
[[:req, :a], [:opt, :b]]
[[:opt, :a], [:opt, :b]]
```

`proc { |a, b| }` and `lambda { |a, b| }` both reported `2`. `*a` printed `-1`, and one required plus one optional parameter printed `-2`: in both measurements the negative value was the negation of the required parameter count plus one. `parameters` shows the difference: in the lambda, `a` is required (`:req`), while in the proc the same parameter is optional (`:opt`). The looseness in the section The Difference Between a Proc and a Lambda can thus be read in the object's own definition. **CB46.**

## A Closure Shares the Variable

A lambda carries not the value of the outer local variable but the variable itself. If the variable changes later, the lambda sees the new value; if the lambda writes to the variable, the outer variable changes too.

```ruby
# sharing.rb — a closure and the outer variable
x = 1
reader = -> { x }
x = 5
puts reader.call
writer = -> { x = 9 }
writer.call
puts x
```
```
5
9
```

When `reader` was defined, `x` was `1`; `x` was later set to `5` and `reader.call` gave `5`. The `x = 9` inside `writer` wrote to the outer `x`, and `puts x` printed `9`. A lambda uses the variable from where it was defined, not a copy. **CB47.** The measurement is for top-level locals; the case that crosses a method boundary was measured in the Carrying a Variable section.

## A Lambda with case

A `case` expression tests a `when` condition with `===`. Thanks to `Proc#===`, a lambda can take part in this test directly: `===` calls the lambda with the given value.

```ruby
# case_lambda.rb — a lambda in a when branch
even = ->(n) { n.even? }
[1, 2].each do |n|
  case n
  when even then puts "#{n} even"
  else puts "#{n} odd"
  end
end
puts even === 2
puts "owner=#{even.method(:===).owner}"
```
```
1 odd
2 even
true
owner=Proc
```

`when even` called the lambda for every `n`: for `1` it returned `false`, so `else` ran; for `2` it returned `true`, so the `when` branch ran. `even === 2` gave `true` directly, and the owner of `===` was printed as `Proc`. So when `case` tests the condition, it sends the `===` message to the lambda, and the responder is a class. This ties in with the common question of the Procs and Lambdas lesson: the same callable object can be used with `call`, with `.()`, in place of a block with `&`, and here with `===`; in each, the object itself is the same and only the message changes. **CB54.** The measurement was made with a single-parameter lambda; the behavior of a multi-parameter lambda in a `when` branch was not tried. Since the value of the `===` branch is used in the `case` test itself, it was not assigned to a separate result variable in this measurement.

## The Bounding Measurement

Can we see the difference between a proc and a lambda by looking at the owner of `call`? No: the owner is the same for both kinds, because both are instances of the `Proc` class. The difference is not in the owner but in the object's state.

```ruby
# owner.rb — the owner of the call message is the same for both kinds
loose = proc { |x| x }
strict = lambda { |x| x }
puts "proc    #{loose.method(:call).owner} lambda?=#{loose.lambda?}"
puts "lambda  #{strict.method(:call).owner} lambda?=#{strict.lambda?}"
```
```
proc    Proc lambda?=false
lambda  Proc lambda?=true
```

The owner is `Proc` on both lines; only `lambda?` differs. In the earlier lessons the `owner` question separated which class or module a method is defined in; here, because the two objects are of the same class, the same question does not reveal a difference. Sending the same message to two objects gives not two separate responders but two states of a single responder. So the `owner` question does not show the difference between a proc and a lambda: the class is the same, and the difference is carried by the object's own state. **CB12.** This measurement asks only about the `call` message; whether there is an owner difference for other messages is not measured in this lesson.

## Summary

- A proc and a lambda are two ways of turning a block into an object; both have the class `Proc`.
- This lesson's responder is the **class**: the `Proc` answers the `call` message, and `call`, `.()` and square brackets give the same result.
- A lambda checks the argument count and raises `ArgumentError` on an excess; a proc drops the extra and turns the missing into `nil`.
- The procs obtained from a method object and from a symbol return `true` for `lambda?`.
- The bounding measurement: the owner of `call` is `Proc` for both kinds; the difference is in the `lambda?` state.

## Next Step

A lambda's error was in the argument count. The next lesson moves on to the concept of an error itself: `rescue` is not a method but a construct of the language, and what this construct returns in which expressions will be measured.
