Catching what a block returns (A newbie lesson learned)

R

Richard Lawrence

Hello all,

This is a message intended to be from one newbie to another.

Until last night, I couldn't quite understand something about Ruby
blocks: namely, how to get anything back from them. I have read a
number of tutorials that try to explain blocks, and they always use
trivial examples like this:

def verbose_call(x)
puts "I am calling a block now!"
yield x
puts "I am done calling the block!"
end

and then you can do wonderful things like:

verbose_call(3) {|n| puts n + 1}
verbose_call("Jenny") {|name| puts name + " from the block."}

This is all well and good, but it seemed to me that this couldn't be all
there was to the much-acclaimed power of blocks. Then I saw things like:

[1, 2, 3].inject(4) {|sum, elt| sum + elt} # => 10

and became confused. Clearly, the value returned by the block is
secretly being caught by inject(), then fed back into the block...but
how? This seemed a long way from the trivial examples: there, blocks
were a dead end, but here, there was two-way communication happening
between the method and the block.

The solution (of course) was to realize that "yield" actually evaluates
to something. Thus,

def catch_block_value
result = yield
puts "I got this from the block: ", result
end

Realizing that "yield" evaluates to something I can assign to variables,
etc. was important for getting beyond the trivial examples. In
retrospect, I should have paid more attention to the lesson that
*everything* evaluates in Ruby. I think what I was hung up on is that
"yield" is a keyword (right? at least it looks like one), and hence I
thought of it as mere flow control, not a passage for information.

So, again, totally trivial for all you veterans out there, but I hope
that this clears some things up for someone like me. Is there any
documentation that I can help improve by doing a little write-up of this?

Richard
 
D

dblack

Hi --

Realizing that "yield" evaluates to something I can assign to variables, etc.
was important for getting beyond the trivial examples. In retrospect, I
should have paid more attention to the lesson that *everything* evaluates in
Ruby. I think what I was hung up on is that "yield" is a keyword (right? at
least it looks like one), and hence I thought of it as mere flow control, not
a passage for information.

I'm pleased you worked this out, and it does indeed point you to a
great deal of yield's coolness. And you're right that keyword
expressions, too, always evaluate to something (with the exception of
return, since doing this:

x = return 1

would at best just discard x). It's true even for class and method
definitions: class definition blocks evaluate to the last expression
inside them, and def blocks evaluate to nil. So this:

class C
def m
end
end

evaluates to nil, while this:

class C
1
end

evaluates to 1. (And yes, this feature does actually get used in
slightly more real situations :)


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top