[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

default passed block for method

Niko

3/1/2007 11:41:00 AM


Hi all,

I'm trying to define the missing block given in the context of the
method to avoid the block_given? test on each iteration for yield call.

def self.list_of_relationships(relations, source)
# missing_block_that_yield_would_call = lambda { || true } unless
block_given?
relations.map do |relation|
if yield(peer = relation.send(source))
[peer.display_name, peer.id]
end
end.compact
end


Thanks for your help

niko

12 Answers

dblack

3/1/2007 11:48:00 AM

0

Robert Dober

3/1/2007 11:49:00 AM

0

On 3/1/07, Niko <niko@kingtong.org> wrote:
>
> Hi all,
>
> I'm trying to define the missing block given in the context of the
> method to avoid the block_given? test on each iteration for yield call.
>
> def self.list_of_relationships(relations, source)
> # missing_block_that_yield_would_call = lambda { || true } unless
> block_given?
> relations.map do |relation|
> if yield(peer = relation.send(source))
> [peer.display_name, peer.id]
> end
> end.compact
> end
>
>
> Thanks for your help
>
> niko
>
>
Is the following pattern better for you?
def a &blk
blk ||= proc{true}
blk.call
end

a do
puts "Nice"
end
puts a

HTH
Robert
--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous

Niko

3/1/2007 11:54:00 AM

0

dblack@wobblini.net wrote:
> Hi --
>
> On Thu, 1 Mar 2007, Niko wrote:
>
>>
>> Hi all,
>>
>> I'm trying to define the missing block given in the context of the
>> method to avoid the block_given? test on each iteration for yield call.
>>
>> def self.list_of_relationships(relations, source)
>> # missing_block_that_yield_would_call = lambda { || true } unless
>> block_given?
>> relations.map do |relation|
>> if yield(peer = relation.send(source))
>> [peer.display_name, peer.id]
>> end
>> end.compact
>> end
>
> You would want to do:
>
> def self.list(relations,source,&block)
> block ||= lambda { true } # no need for empty ||
> relations.map do |relation|
> if block.call(peer = ....
>
> etc. You'd have to do some benchmarks to find out whether the
> slowdown from call is worse than the slowdown from block_given?.
>
>
> David
>

it works like a charm
i'll do some benchmarks to check the slowdown

thanks for the help


Brian Candler

3/1/2007 11:55:00 AM

0

On Thu, Mar 01, 2007 at 08:41:19PM +0900, Niko wrote:
> I'm trying to define the missing block given in the context of the
> method to avoid the block_given? test on each iteration for yield call.
>
> def self.list_of_relationships(relations, source)
> # missing_block_that_yield_would_call = lambda { || true } unless
> block_given?
> relations.map do |relation|
> if yield(peer = relation.send(source))
> [peer.display_name, peer.id]
> end
> end.compact
> end

def foo(*args, &blk)
blk ||= lambda { true }
blk.call(*args)
end

p foo("123") { |x| "Look: #{x}" }
p foo("456")

It looks like you can't provide a default value for the block in the direct
way:

def foo(*args, &blk = lambda { true } )
# syntax error, unexpected '=', expecting ')'
end

HTH,

Brian.

Robert Dober

3/1/2007 12:02:00 PM

0

On 3/1/07, Niko <niko@kingtong.org> wrote:
> dblack@wobblini.net wrote:
> > Hi --
> >
> > On Thu, 1 Mar 2007, Niko wrote:
> >
> >>
> >> Hi all,
> >>
> >> I'm trying to define the missing block given in the context of the
> >> method to avoid the block_given? test on each iteration for yield call.
> >>
> >> def self.list_of_relationships(relations, source)
> >> # missing_block_that_yield_would_call = lambda { || true } unless
> >> block_given?
> >> relations.map do |relation|
> >> if yield(peer = relation.send(source))
> >> [peer.display_name, peer.id]
> >> end
> >> end.compact
> >> end
> >
> > You would want to do:
> >
> > def self.list(relations,source,&block)
> > block ||= lambda { true } # no need for empty ||
> > relations.map do |relation|
> > if block.call(peer = ....
> >
> > etc. You'd have to do some benchmarks to find out whether the
> > slowdown from call is worse than the slowdown from block_given?.
> >
> >
> > David
> >
>
> it works like a charm
> i'll do some benchmarks to check the slowdown
>
they are bad unfortunately, I would not have thought of it, great pointing at
that David.
========================================================
require 'benchmark'

def a1
return true unless block_given?
yield
end
def a2 &blk
blk ||= proc{true}
blk.call
end


Benchmark.bmbm do |x|
x.report("block_given?") {
424242.times do
a1 { 'hi' }
a1
end
}
x.report("&blk") {
424242.times do
a2 { 'hi' }
a2
end
}
end
--------------->

Rehearsal ------------------------------------------------
block_given? 1.280000 0.000000 1.280000 ( 1.310912)
&blk 7.060000 0.020000 7.080000 ( 10.477620)
--------------------------------------- total: 8.360000sec

user system total real
block_given? 1.280000 0.000000 1.280000 ( 1.284248)
&blk 7.090000 0.010000 7.100000 ( 9.274008)

==================================================================
> thanks for the help
>
>
>


--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous

Joel VanderWerf

3/2/2007 12:14:00 AM

0

Robert Dober wrote:
> On 3/1/07, Niko <niko@kingtong.org> wrote:
>> dblack@wobblini.net wrote:
>> > Hi --
>> >
>> > On Thu, 1 Mar 2007, Niko wrote:
>> >
>> >>
>> >> Hi all,
>> >>
>> >> I'm trying to define the missing block given in the context of the
>> >> method to avoid the block_given? test on each iteration for yield
>> call.
>> >>
>> >> def self.list_of_relationships(relations, source)
>> >> # missing_block_that_yield_would_call = lambda { || true } unless
>> >> block_given?
>> >> relations.map do |relation|
>> >> if yield(peer = relation.send(source))
>> >> [peer.display_name, peer.id]
>> >> end
>> >> end.compact
>> >> end
>> >
>> > You would want to do:
>> >
>> > def self.list(relations,source,&block)
>> > block ||= lambda { true } # no need for empty ||
>> > relations.map do |relation|
>> > if block.call(peer = ....
>> >
>> > etc. You'd have to do some benchmarks to find out whether the
>> > slowdown from call is worse than the slowdown from block_given?.
>> >
>> >
>> > David
>> >
>>
>> it works like a charm
>> i'll do some benchmarks to check the slowdown
>>
> they are bad unfortunately, I would not have thought of it, great
> pointing at
> that David.
> ========================================================
> require 'benchmark'
>
> def a1
> return true unless block_given?
> yield
> end
> def a2 &blk
> blk ||= proc{true}
> blk.call
> end
>
>
> Benchmark.bmbm do |x|
> x.report("block_given?") {
> 424242.times do
> a1 { 'hi' }
> a1
> end
> }
> x.report("&blk") {
> 424242.times do
> a2 { 'hi' }
> a2
> end
> }
> end
> --------------->
>
> Rehearsal ------------------------------------------------
> block_given? 1.280000 0.000000 1.280000 ( 1.310912)
> &blk 7.060000 0.020000 7.080000 ( 10.477620)
> --------------------------------------- total: 8.360000sec
>
> user system total real
> block_given? 1.280000 0.000000 1.280000 ( 1.284248)
> &blk 7.090000 0.010000 7.100000 ( 9.274008)
>
> ==================================================================

That's not really fair to David's suggestion, though, since in the
benchmark you put the loop around the block creation (so you are really
stressing Proc.new). This seems closer to the original example:


require 'benchmark'

def a1 n
n.times do
if block_given?
yield
end
end
end

def a2 n, &blk
blk ||= proc{true}
n.times do
blk.call
end
end


Benchmark.bmbm do |x|
x.report("block_given?") {
a1(424242) { 'hi' }
}
x.report("&blk") {
a2(424242) { 'hi' }
}
end



Rehearsal ------------------------------------------------
block_given? 0.633333 0.000000 0.633333 ( 0.389330)
&blk 1.050000 0.000000 1.050000 ( 0.622025)
--------------------------------------- total: 1.683333sec

user system total real
block_given? 0.650000 0.000000 0.650000 ( 0.384855)
&blk 1.033333 0.000000 1.033333 ( 0.621509)



--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Robert Dober

3/2/2007 9:34:00 AM

0

On 3/2/07, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
> Robert Dober wrote:
> > On 3/1/07, Niko <niko@kingtong.org> wrote:
> >> dblack@wobblini.net wrote:
> >> > Hi --
> >> >
> >> > On Thu, 1 Mar 2007, Niko wrote:
> >> >
> >> >>
> >> >> Hi all,
> >> >>
> >> >> I'm trying to define the missing block given in the context of the
> >> >> method to avoid the block_given? test on each iteration for yield
> >> call.
> >> >>
> >> >> def self.list_of_relationships(relations, source)
> >> >> # missing_block_that_yield_would_call = lambda { || true } unless
> >> >> block_given?
> >> >> relations.map do |relation|
> >> >> if yield(peer = relation.send(source))
> >> >> [peer.display_name, peer.id]
> >> >> end
> >> >> end.compact
> >> >> end
> >> >
> >> > You would want to do:
> >> >
> >> > def self.list(relations,source,&block)
> >> > block ||= lambda { true } # no need for empty ||
> >> > relations.map do |relation|
> >> > if block.call(peer = ....
> >> >
> >> > etc. You'd have to do some benchmarks to find out whether the
> >> > slowdown from call is worse than the slowdown from block_given?.
> >> >
> >> >
> >> > David
> >> >
> >>
> >> it works like a charm
> >> i'll do some benchmarks to check the slowdown
> >>
> > they are bad unfortunately, I would not have thought of it, great
> > pointing at
> > that David.
> > ========================================================
> > require 'benchmark'
> >
> > def a1
> > return true unless block_given?
> > yield
> > end
> > def a2 &blk
> > blk ||= proc{true}
> > blk.call
> > end
> >
> >
> > Benchmark.bmbm do |x|
> > x.report("block_given?") {
> > 424242.times do
> > a1 { 'hi' }
> > a1
> > end
> > }
> > x.report("&blk") {
> > 424242.times do
> > a2 { 'hi' }
> > a2
> > end
> > }
> > end
> > --------------->
> >
> > Rehearsal ------------------------------------------------
> > block_given? 1.280000 0.000000 1.280000 ( 1.310912)
> > &blk 7.060000 0.020000 7.080000 ( 10.477620)
> > --------------------------------------- total: 8.360000sec
> >
> > user system total real
> > block_given? 1.280000 0.000000 1.280000 ( 1.284248)
> > &blk 7.090000 0.010000 7.100000 ( 9.274008)
> >
> > ==================================================================
>
> That's not really fair to David's suggestion, though, since in the
Well I benchmarked my suggestion, not David's, probably made another
mistake in my "where to put the post".
However I felt that they were equivalent, do you agree?
> benchmark you put the loop around the block creation (so you are really
> stressing Proc.new).
Good point, I was missing that Proc.new was so costly and not #call !
But are we not unfair to #block_given? now?

Actually I tried to benchmark the difference between #call and #yield
only and one can see that
block_given? comes almost for free, as I have shown all too well #proc
is very expensive :(.

Therefore your results are pretty correct although you call
block_given way to often, but as it is so cheap..., did you know
maybe?

Thanks in any case for pointing out my error which was *big*.

Cheers
Robert

<snip>
--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous

Rick DeNatale

3/2/2007 6:22:00 PM

0

Just for giggles, I combined Robert and Joel's benchmarks and ran them
on both ruby 1.8 and a quite recent 1.9. Perhaps the results are of
interest.

rick@frodo:/public/rubyscripts$ ruby1.8 blkgiven.rb
Rehearsal -----------------------------------------------------
rd - block_given? 6.070000 1.620000 7.690000 ( 15.323920)
jv - block_given? 3.530000 0.530000 4.060000 ( 9.952521)
rd - &blk 29.620000 2.090000 31.710000 ( 55.018634)
jv - &blk 8.580000 1.400000 9.980000 ( 13.505903)
------------------------------------------- total: 53.440000sec

user system total real
rd - block_given? 6.430000 1.550000 7.980000 ( 12.312925)
jv - block_given? 3.470000 0.630000 4.100000 ( 7.956797)
rd - &blk 28.920000 2.040000 30.960000 ( 55.456023)
jv - &blk 8.860000 1.350000 10.210000 ( 12.264554)


rick@frodo:/public/rubyscripts$ ruby1.9 blkgiven.rb
Rehearsal -----------------------------------------------------
rd - block_given? 1.950000 0.000000 1.950000 ( 2.503581)
jv - block_given? 1.930000 0.010000 1.940000 ( 3.029174)
rd - &blk 10.870000 0.020000 10.890000 ( 21.230573)
jv - &blk 2.430000 0.000000 2.430000 ( 6.296742)
------------------------------------------- total: 17.210000sec

user system total real
rd - block_given? 2.040000 0.010000 2.050000 ( 3.862906)
jv - block_given? 1.770000 0.000000 1.770000 ( 2.239562)
rd - &blk 10.520000 0.050000 10.570000 ( 17.941764)
jv - &blk 2.450000 0.010000 2.460000 ( 3.961397)
rick@frodo:/public/rubyscripts$
---
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Robert Dober

3/2/2007 6:53:00 PM

0

On 3/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:
> Just for giggles, I combined Robert and Joel's benchmarks and ran them
> on both ruby 1.8 and a quite recent 1.9. Perhaps the results are of
> interest.
>
> rick@frodo:/public/rubyscripts$ ruby1.8 blkgiven.rb
> Rehearsal -----------------------------------------------------
> rd - block_given? 6.070000 1.620000 7.690000 ( 15.323920)
> jv - block_given? 3.530000 0.530000 4.060000 ( 9.952521)
> rd - &blk 29.620000 2.090000 31.710000 ( 55.018634)
> jv - &blk 8.580000 1.400000 9.980000 ( 13.505903)
> ------------------------------------------- total: 53.440000sec
>
> user system total real
> rd - block_given? 6.430000 1.550000 7.980000 ( 12.312925)
> jv - block_given? 3.470000 0.630000 4.100000 ( 7.956797)
> rd - &blk 28.920000 2.040000 30.960000 ( 55.456023)
> jv - &blk 8.860000 1.350000 10.210000 ( 12.264554)
>
>
> rick@frodo:/public/rubyscripts$ ruby1.9 blkgiven.rb
> Rehearsal -----------------------------------------------------
> rd - block_given? 1.950000 0.000000 1.950000 ( 2.503581)
> jv - block_given? 1.930000 0.010000 1.940000 ( 3.029174)
> rd - &blk 10.870000 0.020000 10.890000 ( 21.230573)
> jv - &blk 2.430000 0.000000 2.430000 ( 6.296742)
> ------------------------------------------- total: 17.210000sec
>
> user system total real
> rd - block_given? 2.040000 0.010000 2.050000 ( 3.862906)
> jv - block_given? 1.770000 0.000000 1.770000 ( 2.239562)
> rd - &blk 10.520000 0.050000 10.570000 ( 17.941764)
> jv - &blk 2.450000 0.010000 2.460000 ( 3.961397)
> rick@frodo:/public/rubyscripts$
> ---
> Rick DeNatale
>
> My blog on Ruby
> http://talklikeaduck.denh...
>
>

Rick I think as a matter of fact that both benchmarks are important.
I was too humble, but that will not happen again ;)

Let us look at Joël's first, it applies to the following pattern:

def method &blk
blk ||= proc{true}
MANY.times do
...
blk.call
...
end
end

from the performance POV you can get away with it.
==================================================
my naive benchmark was benchmarking the following pattern - which
exits quite often too.

def method &blk
blk ||= proc{ true }
...
blk.call
...
end

Now of course the proc is a killer as we have as many proces as #call :(

Hopefully this kind of a reasonable conclusion about the performance
cost of the whole stuff.

Cheers
Robert

--
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important things.
-Anonymous

Rick DeNatale

3/2/2007 9:37:00 PM

0

On 3/2/07, Robert Dober <robert.dober@gmail.com> wrote:
> On 3/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:
> > Just for giggles, I combined Robert and Joel's benchmarks and ran them
> > on both ruby 1.8 and a quite recent 1.9. Perhaps the results are of
> > interest.
> >
> > rick@frodo:/public/rubyscripts$ ruby1.8 blkgiven.rb
> > Rehearsal -----------------------------------------------------
> > rd - block_given? 6.070000 1.620000 7.690000 ( 15.323920)
> > jv - block_given? 3.530000 0.530000 4.060000 ( 9.952521)
> > rd - &blk 29.620000 2.090000 31.710000 ( 55.018634)
> > jv - &blk 8.580000 1.400000 9.980000 ( 13.505903)
> > ------------------------------------------- total: 53.440000sec
> >
> > user system total real
> > rd - block_given? 6.430000 1.550000 7.980000 ( 12.312925)
> > jv - block_given? 3.470000 0.630000 4.100000 ( 7.956797)
> > rd - &blk 28.920000 2.040000 30.960000 ( 55.456023)
> > jv - &blk 8.860000 1.350000 10.210000 ( 12.264554)
> >
> >
> > rick@frodo:/public/rubyscripts$ ruby1.9 blkgiven.rb
> > Rehearsal -----------------------------------------------------
> > rd - block_given? 1.950000 0.000000 1.950000 ( 2.503581)
> > jv - block_given? 1.930000 0.010000 1.940000 ( 3.029174)
> > rd - &blk 10.870000 0.020000 10.890000 ( 21.230573)
> > jv - &blk 2.430000 0.000000 2.430000 ( 6.296742)
> > ------------------------------------------- total: 17.210000sec
> >
> > user system total real
> > rd - block_given? 2.040000 0.010000 2.050000 ( 3.862906)
> > jv - block_given? 1.770000 0.000000 1.770000 ( 2.239562)
> > rd - &blk 10.520000 0.050000 10.570000 ( 17.941764)
> > jv - &blk 2.450000 0.010000 2.460000 ( 3.961397)
> > rick@frodo:/public/rubyscripts$
> > ---
> > Rick DeNatale
> >
> > My blog on Ruby
> > http://talklikeaduck.denh...
> >
> >
>
> Rick I think as a matter of fact that both benchmarks are important.
> I was too humble, but that will not happen again ;)
>
> Let us look at Joël's first, it applies to the following pattern:
>
> def method &blk
> blk ||= proc{true}
> MANY.times do
> ...
> blk.call
> ...
> end
> end
>
> from the performance POV you can get away with it.
> ==================================================
> my naive benchmark was benchmarking the following pattern - which
> exits quite often too.
>
> def method &blk
> blk ||= proc{ true }
> ...
> blk.call
> ...
> end
>
> Now of course the proc is a killer as we have as many proces as #call :(
>
> Hopefully this kind of a reasonable conclusion about the performance
> cost of the whole stuff.
>

I was suggesting that an analysis of how the relative numbers are
changing between 1.8 and 1.9 might be interesting.

Besides the fact that YARV seems quite a bit faster overall, I think
that some of the rules of thumb based on benchmarking on the 'classic'
Ruby implementation are going to change for the new Ruby.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...