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?

···

--
Posted via http://www.ruby-forum.com/.

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 Stowbunenko <lists@ruby-forum.com>wrote:

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?

--
Posted via http://www.ruby-forum.com/\.

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.

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.

Check.

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.

Check.

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.

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@(irb):9>
(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"

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.

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

···

On Fri, Apr 12, 2013 at 10:12 PM, Vincent Stowbunenko <lists@ruby-forum.com>wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

http://codelikethis.com/lessons/ruby_blocks/blocks 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