Default passed block for method

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

Hi --

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

···

On Thu, 1 Mar 2007, Niko wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

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

···

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

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

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.

···

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

dblack@wobblini.net wrote:

Hi --

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

···

On Thu, 1 Mar 2007, Niko wrote:

they are bad unfortunately, I would not have thought of it, great pointing at
that David.

···

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

========================================================
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

Robert Dober wrote:

> Hi --
>
>>
>> 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)

···

On 3/1/07, Niko <niko@kingtong.org> wrote:

dblack@wobblini.net wrote:
> On Thu, 1 Mar 2007, Niko wrote:

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

Robert Dober wrote:
>> > Hi --
>> >
>> >>
>> >> 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>

···

On 3/2/07, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

> On 3/1/07, Niko <niko@kingtong.org> wrote:
>> dblack@wobblini.net wrote:
>> > On Thu, 1 Mar 2007, Niko wrote:

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

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.denhaven2.com/

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

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.

···

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.denhaven2.com/

==================================================
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 :frowning:

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

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.

···

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.denhaven2.com/
>

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

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

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

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

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.

I thought so Rick, but they seem identical, I mean the same factor of
slowfown for proc and call, right?
Just that YARV runs quite faster :slight_smile:

···

On 3/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

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

>
> 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.
>
I thought so Rick, but they seem identical, I mean the same factor of
slowfown for proc and call, right?
Just that YARV runs quite faster :slight_smile:

Not really, here's a cross tabulation (formatting likely to get screwed up)

                             1.8 1.9 ratio 1.8/1.9
rd -block_given? 6.43 2.04 3.15
rd -&blk 28.92 10.52 2.75
ratio 4.5 5.16
      
jv – block_given? 3.47 1.77 1.96
jv – &blk 8.86 2.45 3.62
ratio 2.55 1.38

So for your (Robert's) version of the benchmark the difference between
the two approaches has widened in 1.9, while in Joel's it has
narrowed.

Significant? I don't know, but interesting.

···

On 3/2/07, Robert Dober <robert.dober@gmail.com> wrote:

On 3/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:

> --
> Rick DeNatale
>
> My blog on Ruby
> http://talklikeaduck.denhaven2.com/
>

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

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/