Pass block to a method call?

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

Jeff Davis wrote:

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.

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 :slight_smile:

Cheers,
Navin.

···

Jeff Davis <jdavis-list@empires.org> wrote:

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

···

On Sun, 30 Jan 2005 07:34:10 +0900, Jeff Davis <jdavis-list@empires.org> wrote:
--
Austin Ziegler * halostatue@gmail.com
               * Alternate: austin@halostatue.ca

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

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.

···

Jeff Davis <jdavis-list@empires.org> wrote:

"Jeff Davis" <jdavis-list@empires.org> schrieb im Newsbeitrag news:41FC2458.4060009@empires.org...

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?

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