Forum: Ruby Passing code blocks to methods and debugging

0946b736110f6af95c93bce0ea6d46ff?d=identicon&s=25 Gerald Vim (gvim)
on 2013-11-01 19:49
(Received via mailing list)
I'm fairly new to Ruby, puzzling the value of:

def sub1(x)
   yield 5 * x
end

sub1(2) {|y| puts 3 * y }    #=> 30

.... over:

def sub2(x)
   y = 5 * x
   puts 3 * y
end

sub2(2)   #=> 30

Isn't there the danger,  with passing code blocks, that half of your
method/function/sub definition is hanging somewhere else in your code
making it difficult to keep track of exactly what it does? How can I
debug a method if I don't know what else it's composed of until it is
called?

gvim
14b5582046b4e7b24ab69b7886a35868?d=identicon&s=25 Joel Pearson (virtuoso)
on 2013-11-01 20:34
Ruby will trace the source of exceptions back to either the block or the
method, so there's no problem there.
As for as debugging, that's down to you to modify the code by adding "p"
or "puts thing.inspect" in order to narrow down the source of an issue.

The main reason for using blocks is flexibility, and a great example is
"File.open". If you open a file without using a block, you must remember
to close it or you risk locking access to the file.
If you use a block, then the method can handle the before and after
(opening and closing the file), while giving the caller full control
over what happens to the file in between.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-11-02 14:17
(Received via mailing list)
On Fri, Nov 1, 2013 at 7:48 PM, gvim <gvimrc@gmail.com> wrote:
> def sub2(x)
>   y = 5 * x
>   puts 3 * y
> end
>
> sub2(2)   #=> 30
>
> Isn't there the danger,  with passing code blocks, that half of your
> method/function/sub definition is hanging somewhere else in your code making
> it difficult to keep track of exactly what it does? How can I debug a method
> if I don't know what else it's composed of until it is called?

But that is true for _any_ method.  Blocks are just anonymous
functions.  In the same way as named functions and methods you need to
properly define what a method should do and what other methods should
do.  Joel gave an example: File.open is responsible for opening and
closing the file while the block passed may do whatever it needs to do
with the open File object (e.g. writing or reading).

Another example is Array#each: it is responsible for iterating all
elements. The block passed can do whatever it needs to do with the
current element.  Your piece of code would probably be badly
structured with a second method regardless whether it's a block or
another function - as long as you want to calculate and output 3*5*x.
If you often need to calculate 5*x then the approach with the block
might be better. But the example is really somewhat artificial.

Long time ago I wrote two blog articles which you might find helpful.
http://blog.rubybestpractices.com/posts/rklemme/00...
http://blog.rubybestpractices.com/posts/rklemme/00...

Kind regards

robert
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.