Understand the difference between implicit and explicit blocks

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the ruby category.

Last Updated: 2021-05-16

I wrote this function

def add_multi_domain(items, filter_block = ->(store) {true})
  items.filter(&filter_block)
end

I called it as such:

add_multi_domain([3,4,8,9])  {|n| n < 5 }

The result was: [3,4,8,9] - i.e. the presence of the 9 meant it did not run with the block I fed in at call time - instead it used the default.

The issue was that the caller had an implicit block (which expects a yield in the method and has no block parameter in the signature), whereas the method I actually defined had an explicit block argument in mind.

Thus the following caller (note the comma) would have worked with my code:

add_multi_domain([3,4,8,9]), -> {n}  { n < 5 }
# [3,4], i.e. it works with a proc

Defining the parameter name to have an ampersand in front also worked:

def add_multi_domain(items, &filter_block)
  items.filter(&filter_block)
end
add_multi_domain([3,4,8,9])  {|n| n < 5 }
# => [3,4] , as expected