[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

pass block to a method call?

Jeff Davis

1/29/2005 10:34:00 PM

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


6 Answers

Florian Gross

1/29/2005 10:58:00 PM

0

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.

Navindra Umanee

1/29/2005 11:05:00 PM

0

Jeff Davis <jdavis-list@empires.org> wrote:
> 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.


Austin Ziegler

1/29/2005 11:06:00 PM

0

On Sun, 30 Jan 2005 07:34:10 +0900, 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
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca


Jeff Davis

1/30/2005 12:04:00 AM

0


>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



Navindra Umanee

1/30/2005 12:12:00 AM

0

Jeff Davis <jdavis-list@empires.org> wrote:
> 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...

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

Cheers,
Navin.


Robert Klemme

1/30/2005 2:40:00 PM

0


"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