pass block to a method call?

J

Jeff Davis

I know I can define a method like:

def foo(&p)
p.call
end

or:

def foo
yield
end

First, what's the difference between those two? I can pass a block to
either.

Also, how do I make the block optional? I would like to make a method
that performs it's task as usual, but you could also pass it a block
that it can use.

And also, can you pass more than one block to the same method? Is it
only the last argument?

And what's the difference between:
proc { puts 'foo'}
and:
{ puts 'foo' }
?

Is "proc" a keyword that turns the block into a value, or is the block
already a value and it's being passed to "proc" to turn it into a Proc
object?

Perhaps I'm not understanding blocks and iterators all that well.

Thanks,
Jeff Davis
 
F

Florian Gross

Jeff said:
I know I can define a method like:

def foo(&p)
p.call
end

or:

def foo
yield
end

First, what's the difference between those two? I can pass a block to
either.

They pretty much do the same. The first will turn the block into an
object you can assign to variables and so on, however.
Also, how do I make the block optional? I would like to make a method
that performs it's task as usual, but you could also pass it a block
that it can use.

It already is optional when you do the above. In the &p case p can be
nil and in the yield one you will get a LocalJumpError if the block is
not there. (You can use block_given?() to check for the block in the
latter case.)
And also, can you pass more than one block to the same method? Is it
only the last argument?

You can only use the block passing syntax for one block. It's however
possible to do something like this:

def x(y, &z) y.call(z.call()) end
x(lambda { ... }) { ... }
And what's the difference between:
proc { puts 'foo'}
and:
{ puts 'foo' }
?

Is "proc" a keyword that turns the block into a value, or is the block
already a value and it's being passed to "proc" to turn it into a Proc
object?

Blocks are already values, but they are implicitly passed around by
default. lambda (or proc or Proc.new) will convert such a block into an
actual Object which you can store in variables or call methods on.
 
N

Navindra Umanee

Jeff Davis said:
I know I can define a method like:

def foo(&p)
p.call
end

You can also use "yield" here instead of p.call.
or:

def foo
yield
end

First, what's the difference between those two? I can pass a block to
either.

The only difference is that in the second case the block is anonymous.
In the first case, it has a name and so you can pass it around if you
want (e.g. recursively).
Also, how do I make the block optional? I would like to make a method
that performs it's task as usual, but you could also pass it a block
that it can use.

Use a "block_given?" test in your method:

def foo(&p)
if block_given?
yield
else
p "foo"
end
end
And also, can you pass more than one block to the same method? Is it
only the last argument?

No, but you can pass more than one proc objects (functions) to the
method. Yes, only the last one can be the official "block".

(I wrote up to here before I saw Florian's answer :)

Cheers,
Navin.
 
A

Austin Ziegler

I know I can define a method like:
def foo(&p)
p.call
end
def foo
yield
end
First, what's the difference between those two? I can pass a block to
either.

In the former case, the block is silently converted to a Proc object
(there is a difference -- I'm not sure what -- between a Proc object
created with #proc or #lambda and a Proc object created with
Proc.new). In the latter case, it's not actually turned into an
object. It is easier to pass a Proc object downstream than a block,
unless the natural inclination in all cases is to yield. That is:

def foo
self.each { yield } # yields to the provided block, from within
# the block for #each.
end
Also, how do I make the block optional? I would like to make a
method that performs it's task as usual, but you could also pass
it a block that it can use.

Two ways, depending on what you do:

def foo(&p)
p.call if p
end

def foo
yield if block_given? # a method of Kernel
end

And also, can you pass more than one block to the same method? Is
it only the last argument?

You can, but they must be regular parameters, and they must
explicitly be Proc objects:

def foo(cb1 = nil, cb2 = nil)
cb1.call if cb1
cb2.call if cb2
end

And what's the difference between:
proc { puts 'foo'}
and:
{ puts 'foo' }
?

Thee former creates a Proc object. The latter is just a block and is
valid only after a method call.

-austin
 
J

Jeff Davis

The only difference is that in the second case the block is anonymous.
In the first case, it has a name and so you can pass it around if you
want (e.g. recursively).
That brings up another question: how do you call a function that accepts
a block if all you have is a proc object?

i.e. what's the difference between the following:
def foo(&p) p.call; end
foo { puts 'foo' }
and:
def foo(&p) p.call; end
p = proc { puts 'foo' }
foo { p.call }

Are those the same? Is the latter the proper way to pass a proc object
as a block?

Thanks to all for your help. I'm just getting into Ruby and I really
like it so far (coming from Python/Perl/PHP).

Regards,
Jeff Davis
 
N

Navindra Umanee

Jeff Davis said:
That brings up another question: how do you call a function that accepts
a block if all you have is a proc object?

i.e. what's the difference between the following:
def foo(&p) p.call; end
foo { puts 'foo' }
and:
def foo(&p) p.call; end
p = proc { puts 'foo' }
foo { p.call }

Are those the same? Is the latter the proper way to pass a proc object
as a block?

Yes they're the same. You know about "irb" right? You can try these
out interactively like you do in Python. An easier way to handle the
second call to foo is simply:

foo(&p)

The & specifies it's a block and is always the last argument. You can
even do that when foo uses anonymous blocks.
Thanks to all for your help. I'm just getting into Ruby and I really
like it so far (coming from Python/Perl/PHP).

I really recommend the pickaxe book if you haven't read it:

http://www.rubycentral.com/book/

A more recent and up-to-date version is for sale.

Cheers,
Navin.
 
R

Robert Klemme

Jeff Davis said:
That brings up another question: how do you call a function that accepts a
block if all you have is a proc object?

i.e. what's the difference between the following:
def foo(&p) p.call; end
foo { puts 'foo' }
and:
def foo(&p) p.call; end
p = proc { puts 'foo' }
foo { p.call }

Are those the same? Is the latter the proper way to pass a proc object as
a block?

As others have pointed out already this one is better (and IMHO faster
although I did not test that):

irb(main):006:0> def f(&b) b.call end
=> nil
irb(main):007:0> foo = lambda {puts "ja"}
=> #<Proc:0x101a84f8@(irb):7>
irb(main):008:0> f &foo
ja
=> nil

I think nobody mentioned this before (sorry, if I overread that): An
advantage of the idiom "&b" is that you can easily pass on a block:

def g(&b) b.call end
def f(&b) g &b end

irb(main):009:0> def g(&b) b.call end
=> nil
irb(main):010:0> def f(&b) g &b end
=> nil
irb(main):011:0> f { puts "ja" }
ja
=> nil
Thanks to all for your help. I'm just getting into Ruby and I really like
it so far (coming from Python/Perl/PHP).

You're welcome!

Kind regards

robert
 

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,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top