Trying to understand blocks

I am confused about what is going on with this code:

def foo
yield(“Jim”)
end

def bar
baz = lambda { |n| n.upcase }
foo(&baz)
end

bar # => “JIM”

From what I understand where this is going:

  1. The method bar is being called.

  2. Inside the bar method, the lambda function is being assigned to the
    baz variable, to upcase whatever is assigned to the variable n inside
    the lambda function.

  3. I don’t understand the use of ampersand operator associated with the
    variable baz. Whatever that is, it is an argument for the foo method.

  4. Inside the foo method, it uses a yield function with an argument
    “Jim”. Somehow, the string “Jim” made it way to assign to the variable
    n, upcasing it.

Can anyone help me clarify what this code is really doing?

Blocks are special arguments to methods. You can pass blocks 3 ways*

foo { puts “bar” }
foo do
puts “bar”
end

proc = lambda { puts “bar” }
foo(&proc)

The reason for the & in the 3rd example is to tell ruby that this
argument
is actually this “special” block parameter.

The yield method knows to look for this special parameter and call it.

On Fri, Apr 12, 2013 at 4:12 PM, Vincent S.

On Fri, Apr 12, 2013 at 10:12 PM, Vincent S.
[email protected]wrote:

I am confused about what is going on with this code:

IMO the most important aspect to remember about this is that a block is
an
anonymous function.

From what I understand where this is going:

  1. The method bar is being called.

Check.

  1. Inside the bar method, the lambda function is being assigned to the
    baz variable, to upcase whatever is assigned to the variable n inside
    the lambda function.

Check.

  1. I don’t understand the use of ampersand operator associated with the
    variable baz. Whatever that is, it is an argument for the foo method.

The ampersand is used in two ways: one way presented by you here at the
calling site to pass a block (or something which implements #to_proc) to
a
method. The other one is inside methods to access the block as an
object:

irb(main):008:0> def f(&b) p b; yield 1; b.call(2); b[3] end
=> nil
irb(main):009:0> f {|x| printf “(%p)\n”, x}
#Proc:0x8b19358@:9(irb)
(1)
(2)
(3)
=> nil

When accessing the block as object it can be stored somewhere (e.g. in a
member variable) for later use. That’s the main advantage.

irb(main):010:0> o = Object.new
=> #Object:0x8b265e4
irb(main):011:0> def o.to_proc; lambda {|y| p y} end
=> nil
irb(main):012:0> f(&o)
#<Proc:0x8b3e810@(irb):11 (lambda)>
1
2
3
=> 3

#to_proc is a special mechanism which allows to pass arbitrary things as
a
block, for example:

irb(main):013:0> (1…4).map(&:to_s)
=> [“1”, “2”, “3”, “4”]

Here method #to_proc of the symbol “to_s” invoked. It returns a block
with
a single argument which invokes the method represented by the given name
on
the object:

irb(main):014:0> b = :to_s.to_proc
=> #Proc:0x8b4c4ec
irb(main):015:0> b.call 123
=> “123”

  1. Inside the foo method, it uses a yield function with an argument

“Jim”. Somehow, the string “Jim” made it way to assign to the variable
n, upcasing it.

Keyword “yield” is used to invoke a block passed to the method; since
the
method does not have a name there must be a standard way to invoke it.
The
other ways I have also shown in line 1 above.

A few other aspects
http://blog.rubybestpractices.com/posts/rklemme/001-Using_blocks_for_Robustness.html
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html

Kind regards

robert

Blocks - Code Like This has slides and a
video lecture that might help you out.

Basically, yield is calling an anonymous, invisible function pointer.
It’s sort of like

def foo(p)
p.call(“Jim”)
end

def bar
baz = lambda { |n| n.upcase }
foo(baz)
end

The & turns a proc into a block and back again.

It’s one of the oddest parts of Ruby and it’s almost (but not
entirely) syntactic sugar so you can use “do” blocks to make your code
look cool. (Not a dis: I think it’s great, but it is confusing.)

  • A