Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I pass a block variable to inject?

Tags:

ruby

Given,

  def wrapper &block
    (1..5).inject yield
  end

  proc = Proc.new {|sum, n| sum + n }

Why can't I do this call?

  wrapper &proc
  => NoMethodError: undefined method `+' for nil:NilClass

When looking inside, I see that inject has not been able to assign the memo or the obj, as rewriting the proc to be proc = Proc.new {|memo, obj| puts memo ; puts obj } returns 10 iterations of nothing. I also noted that (1..5).inject takes only one argument, what it passes in as the initial memo, and that technically it doesn't the block as a real argument.

like image 862
Alex Moore-Niemi Avatar asked Feb 13 '23 13:02

Alex Moore-Niemi


1 Answers

The way to do it is

def wrapper &block
  ( 1..5 ).reduce &block
end

p = proc { |a, b| a + b }

wrapper &p
#=> 15

But in your question, you interestingly attempted to use yield. When you use yield, you don't need to explicitly mention the &block parameter – a method cannot refuse a block, which is always callable by yield inside the method. However, yield expects arguments. The way to use yield to achieve your goal is:

def wrapper_2
  ( 1..5 ).reduce { |accumulator, input| yield accumulator, input }
end

This formulation is still a bit awkward. It turns out that there is a secret way to obtain the block inside a method even if you do not specify the &block parameter, and that is by using unadorned Proc.new inside the method:

def wrapper_3
  ( 1..5 ).reduce &Proc.new
end
like image 122
Boris Stitnicky Avatar answered Feb 15 '23 01:02

Boris Stitnicky