#---Proc and Lambda---

Procs and Lambdas are similar to blocks in that they too are anonymous functions.

But blocks have limitations:

  • They can’t be assigned to a variable
  • You can only pass at most one block to a function
  • They can’t be returned from a function
  • They can’t be passed to another proc/function
  • They are not objects

Which is why we have procs and lambdas. They are proper object representations of a ruby block.

Creating a Proc

Here’s how you create a block that’s a proc, using the proc method:

one_adder = proc { |x| x + 1 }
p one_adder # #<Proc:0x000000011bd93408 sample2.rb:8>

And here’s how you’ll call this proc that’s assigned to a variable:

p one_adder.call(41) # => 42

You can also call it in these other shorthand ways:

p one_adder.(41) # => 42
p one_adder[41] # => 42

Creating a Lambda

Here’s how you create a block that’s a lambda:

perimeter = lambda { |l, b| 2 * (l + b) }
p perimeter
## #<Proc:0x000000011deb32a0 sample2.rb:11 (lambda)>
p perimeter.(3, 6) # => 18

The words proc and lambda in the examples above are not ruby keywords. They are methods in the Kernel module.

You can use the “stabby lambda” syntax ->() {} to create a lambda concisely:

perimeter = ->(l, b) { 2 * (l + b) }
p perimeter.(3, 6) # => 18

Converting a Block to a Proc

When a function is passed a block, and if that block needs to be passed as argument to yet another function, then you’ll have to convert the passed in block to a proc.

That’s done by capturing the block in a variable prefixed with & in the function’s signature.

Function block_to_proc has no intention of calling the passed in block for its result.

Instead it just wants to pass it as an argument to another function truth_teller.

So it converts the block to a proc and puts it into a variable a_proc_from_a_block with this syntax: &a_proc_from_a_block

def block_to_proc(name, &a_proc_from_a_block)
  hi = truth_teller(a_proc_from_a_block)
  "block_to_proc says to #{name}: #{hi}"
end
def truth_teller(a_proc)
  "#{a_proc.call('Dwayne')}, U can't act"
end
res = block_to_proc('The Rock') do |name|
  "hello #{name}"
end
p res
## "block_to_proc says to The Rock: hello Dwayne,
## U can't act"

Converting a Proc to a Block

Let’s say the truth_teller above is re-defined to work with a block instead of a proc, like so:

def truth_teller
  "#{yield('Dwayne')}, U can't act"
end

Then, in block_to_proc, you’ll have to convert the proc back to block before passing it to truth_teller using the same & syntax quirk:

def block_to_proc(name, &a_proc_from_a_block)
  hi = truth_teller(&a_proc_from_a_block)
  "block_to_proc says to #{name}: #{hi}"
end

Procs vs Lambdas

Procs and Lambdas differ in how they treat the arguments and the keywords return and break.

For the most part, you don’t have to worry about this. Just stick with lambdas if you don’t want to be caught by any surprises.

You can use the lambda? method to find out if a block is a proc or a lambda:

p proc { 'hi' }.lambda? # => false
p -> { 'hi' }.lambda? # => true

Creating an Anon Function with a Symbol

You can create a specific kind of anonymous function with the to_proc method on a symbol.

Example:

to_s_fn = :to_s.to_proc
p to_s_fn
## => #<Proc:0x000000012889dba8(&:to_s) (lambda)>

(Yes it’s weird that you’re creating a lambda with a method called to_proc.)

And the lambda created like this always takes an argument. So you can call it like this:

p to_s_fn.call(123) # => "123"

The result of calling this lambda is the result of calling to_s on the supplied argument 123. The lambda just does this: 123.to_s

Which means, :to_s.proc is just a shortcut for this:

->(x) { x.to_s }

More examples:

even_fn = :even?.to_proc
p even_fn.call(123) # => false
## Same as `123.even?`
upcase_fn = :upcase.to_proc
p upcase_fn.call('ruby examples') # => "RUBY EXAMPLES"

How to_proc Works

What’s the purpose of this? Why do we need this?

In Ruby, there’s a common pattern where you iterate over an array of items, and then call a specific method on that item.

Like this:

a1 = [11, 22, 33]
a2 = ['harry', 'ron']
p a1.map { |e| e.to_s }
p a1.find_all { |e| e.even? }
p a2.map { |e| e.upcase }

This pattern is so common that Ruby provides a way to shorthand this:

p a1.map(&:to_s) # => ["11", "22", "33"]
p a1.find_all(&:even?) # => [22]
p a2.map(&:upcase) # => ["HARRY", "RON"]

The way this works syntactically is, when you prefix certain Ruby things with &, ruby does specific things:

  • prefixing & to a proc, converts it to a block
  • prefixing & to a block, converts it to a proc
  • And, case in point, prefixing & to a symbol, converts it to the specific kind of lambda discussed above, by implicitly calling the to_proc method on the symbol.

Wouldn’t it be useful if there’s such a shorthand for passing the array elements as argument to a function?

## Is there a shorthand for this?
a1.each { |e| puts e }
## a1.each(&:puts) doesn't work

Yes, there is!

a1.each(&method(:puts))

Passing a method’s name to method returns a Method object, which responds to to_proc. So this works. But it’s not as common as the previous examples because, I think, it’s ugly.

What are Closures then?

A closure is a function that captures the environment it was created in.
Blocks, procs and lambdas are all closures because they can access variables from the context they were created in, and these “bounded-to-closures” variables will still be available when the closure is passed around and called later.

Here’s an example:

make_adder is a function that returns, another function. Well, in ruby-speak, it returns a proc:

def make_adder(add_by)
  ->(x) { x + add_by }
end
num = 2
add_by_x = make_adder(num)
p add_by_x.class # => Proc

You can call this proc like this:

p add_by_x.call(5) # => 7

This add_by_x proc is a closure because it carries around the value ‘2’ we passed to create it.

Keep this aside for a minute now. Let’s now create a new function that takes a function (a proc/lambda/block!) as an argument:

def ask_age(name, fn)
  "Hi #{name}, are you #{fn.call(42)}?"
end

Now we can pass the add_by_x we created above, and ask_age will call it with some value and get some other value back.
But note that add_by_x still has the value ‘2’ bound to it. We didn’t pass it as an argument to fn or ask_age, nor does fn have access to the num variable defined outside the ask_age function:

p ask_age('Joe', add_by_x) # => "Hi Joe, are you 44?"

Note: ask_age above is defined to expect a proc in its fn parameter. But if it’s designed to take a block, like so:

def ask_age(name)
  "Hi #{name}, are you #{yield(42)}?"
end

then while calling ask_age you’ll have to convert the proc add_by_x to a block by prefixing it with &:

p ask_age('Joe', &add_by_x) # => "Hi Joe, are you 44?"

Why to bother with Closures?

Don’t fuss too much about this. I’ve been doing this for over a decade, and there never was a jira ticket explaining a dramatic problem caused by, or lack of closures. Just learn to use them and move on.