This blog is part of our Ruby 2.5 series.

irb > def greet irb > yield irb > end => :greet irb > irb > def greet_with_welcome ( & block ) irb > puts 'Welcome' irb > greet ( & block ) irb > end => :greet_with_welcome irb > greet_with_welcome { p 'BigBinary' } Welcome "BigBinary" => "BigBinary"

In Ruby 2.4 when we pass a block to a method, which further passes to another method, Ruby creates a new Proc object by the given block before passing this proc to the another method.

This creates unnecessary objects even when the block parameter is not accessed. It also creates a chain of Proc objects when the block parameter is passed through various methods.

Proc creation is one a heavyweight operation because we need to store all local variables (represented by Env objects in MRI internal) in the heap.

Ruby 2.5 introduced a lazy proc allocation. Ruby 2.5 will not create a Proc object when passing a block to another method. Insead, it will pass the block information. If the block is accessed somewhere else, then it creates a Proc object by the given block.

This results in lesser memory allocation and faster execution.

Ruby 2.4

irb > require 'benchmark' => true irb > def greet irb > yield irb > end => :greet irb > irb > def greet_with_welcome ( & block ) irb > puts 'Welcome' irb > greet ( & block ) irb > end => :greet_with_welcome irb > irb > Benchmark . measure { 1000 . times { greet_with_welcome { 'BigBinary' } } } Welcome Welcome ... ... ... => #<Benchmark::Tms:0x007fe6ab929de0 @label="", @real=0.022295999999187188, @cstime=0.0, @cutime=0.0, @stime=0.01, @utime=0.0, @total=0.01>

Ruby 2.5

irb > require 'benchmark' => true irb > def greet irb > yield irb > end => :greet irb > irb > def greet_with_welcome ( & block ) irb > puts 'Welcome' irb > greet ( & block ) irb > end => :greet_with_welcome irb > irb > Benchmark . measure { 1000 . times { greet_with_welcome { 'BigBinary' } } } Welcome Welcome ... ... ... => #<Benchmark::Tms:0x00007fa4400871b8 @label="", @real=0.004612999997334555, @cstime=0.0, @cutime=0.0, @stime=0.001524000000000001, @utime=0.0030690000000000023, @total=0.004593000000000003>

As we can see, there is considerable improvement in execution time when a block param is passed in Ruby 2.5.

Here is the relevant commit and discussion.