What is Difference between Ruby Blocks, Procs and Lambdas

Having a problem understanding the difference between ruby blocks, procs and lamdas. What are blocks? What is the difference between procs and lambdas? Lets break this down.

BLOCKS

A block is a collection of code enclosed in a do / end statement or between braces { }. They are chunks of code that you can pick up and drop into another method as input or chunk of code that you associate with a method call. If you have used each before to loop through an Enumerable then you have used blocks.

Defining a block

def block_method
puts "we are in the method"
end
block_method { puts "The block is called"}

Here we have defined the method block_method. Below is a the method call after which we pass a block.

Can you guess the output?

Yeah, you guessed right.

> we are in the method

The output is only of the defined method. This is because we have not invoked the block in any way. Lets see how we invoke the block in the next section.

Yielding a block

def my_method
puts "we are in the method"
yield
puts "we are back in the method"
end
my_method { puts "The block is called"}

What really happens in the above code?

First we have created a method called my_method. Then on the next line we print out the string we are in the method . In next line, notice we have used the yield keyword which will find and invoke the block the method was called with.

What happens here, is that yield will go to the method call and execute the block after which control returns to the method, to resume running method body. In our case we have called the method my_method then passed a block using {}. Yield will execute the block code which was passed after calling my_method then method body execution continues.

Passing parameters to a block

What if you want to pass parameters to yield. Think of how you pass arguments to methods like each whenever you give it a block.

[1,2,3].each {|x| puts x*2 }

In this case the each method takes a block that has an argument. How about we do this with our defined block and see how yield takes arguments.

def my_block
yield 2
yield 3
end
my_block {|parameter| puts "parameter is: #{parameter}" }

Here yield will invoke the block passed with the method call. In our case give the block an argument since the block takes a parameter. First round it will invoke the block with parameter being 2. Control resumes to the method and then invokes the block once again this time with parameter being 3.

> parameter is: 2
> parameter is: 3

Some fun facts about blocks

  • Did you know you can call each method on an enumerable and not pass it a block? It will give you back an enumerable object https://ruby-doc.org/core-2.5.0/Enumerator.html#method-i-each
  • Inside blocks you cannot explicitly return, blocks return the last line of execution
  • When calling each method, the last line is usually ignored and the each method returns the original enumerable
  • When calling map, the last line is added into an array which will be returned

PROCS

So what if you want to pass two blocks to your function. How can you save your block into a variable?

Ruby introduces procs so that we are able to pass blocks around. Proc objects are blocks of code that have been bound to a set of local variables.Once bound, the code may be called in different contexts and still access those variables.

Defining procs

You can call new on the Proc class to create a proc . You can use the kernel object proc. Proc method is simply an alias for Proc.new. This can be assigned into a variable.

factor = Proc.new {|n| print n*2 }
or 
factor = proc {|n| print n*2}
//using the proc value
[3,2,1].each(&factor)

>642

We precede the argument with & so that ruby knows that this is a proc and not a variable.

Defining a method that takes in a proc/block

def my_each( &block )
self.length.times do |i|
# and now we can call our new Proc like normal
block.call( self[i] )
end
end
[1,2,3].my_each { |i| puts i*2 }

On our definition, the & converts the block into a proc so we treat the block as a proc inside our method

We no longer use yield since it is possible to pass more than one proc to a method, we have to say which one we are calling.

There are different ways of calling procs in our methods. Using call, () or using [].

LAMBDAS

Can be defined using the method lambda or can be defined as stuby lambda

lamb = lambda {|n| puts 'I am a lambda' }
lamb = -> (n) { puts 'I am a stuby lambda' }

Difference between Procs and Lambdas

  • Procs don’t care about the correct number of arguments, while lambdas will raise an exception.
  • Return and break behaves differently in procs and lambdas
  • Next behaves same way in both procs and lambdas

References

Pluralsight course: Ruby Fundamentals

The vikingscodeschool website: http://www.vikingcodeschool.com/falling-in-love-with-ruby/blocks-procs-and-lambdas

rubyguides.com : http://www.rubyguides.com/2016/02/ruby-procs-and-lambdas/