Is there any way to pass further the "hidden" block?

Like this:

def foo
yield
end

def bar(&brk)
foo(&brk)
end

bar { puts “foo” }

What I want to know is: is there any way to define `bar’ like this:

def bar
foo
end

so that foo will get the block passed to bar? I want to know this
because I learn from
http://www.pluralsight.com/blogs/dbox/archive/2006/05/09/23068.aspx
that the implicit block is much faster than explicitly passing it
as &brk . I know one solution is

def bar
foo { yield }
end

but that create another block, not the original one.

Im not sure I fully understand…

But…

def foo(baz)
baz
end

def bar
foo(yield)
end

bar { ‘fubar’ }
#=> fubar

Perhaps?

Regards,
Lee

On Dec 17, 2:11 am, Chiyuan Z. [email protected] wrote:

bar { puts “foo” }
as &brk . I know one solution is

def bar
foo { yield }
end

but that create another block, not the original one.

The article you mention is not loading for me (nor is googles cached
version), so I’m not sure exactly what you mean. When you pass a block
as a parameter, it’s just an explicit reference to the implicit block,
not a new copy:

def bar(&blk_2)
puts blk_2.object_id
end
def foo(&blk_1)
puts blk_1.object_id
bar(&blk_1)
end
puts “implicit block”
foo { “baz” }
puts “explicit block”
prc = lambda { “baz” }
puts prc.object_id
foo(&prc)

=>

implicit block
-605770738
-605770738
explicit block
-605770758
-605770758
-605770758

Although it is slightly slower to grab a reference to the block, it’s
probably not anything you have to worry about. E.g., it’s only half as
slow over 100,000 calls for this benchmark:

require “benchmark”
def implicit_blk
yield “baz”
end
def explicit_blk(&blk)
blk.call(“baz”)
end
n = 100_000
Benchmark.bm(10) { | x |
x.report(“implicit”) { n.times { implicit_blk { | y | y } } }
x.report(“explicit”) { n.times { explicit_blk { | y | y } } }
}

=>

            user     system      total        real

implicit 0.370000 0.080000 0.450000 ( 0.478676)
explicit 1.200000 0.090000 1.290000 ( 1.324176)

…for me, that’s not anything to be concerned about.

Edit: Ah, the cached version of the article you mention just loaded.
Looks like the author got a larger variance in his benchmark. I just
ran the above benchmark again for 1,000,000 calls (like the article),
with these results:

            user     system      total        real

implicit 3.520000 0.640000 4.160000 ( 5.230353)
explicit 12.180000 0.850000 13.030000 ( 15.966038)

…so indeed, passing an explicit reference to the block seems to be
exponentially slower. However, still, 3 times slower over a million
calls still doesn’t bother me very much. YMMV.

Regards,
Jordan

On Dec 17, 3:11 am, “Chiyuan Z.” [email protected] wrote:

bar { puts “foo” }
as &brk . I know one solution is

def bar
foo { yield }
end

but that create another block, not the original one.

Do you mean, is there a keyword #block to go along with #block_given?
and #yield? As far as I know, there is no way to pass the block except
via an explicit reference.

But I think explicit may be the future. I’m pretty sure I’ve heard
some chatter about getting rid of #block_given? Technically I would
think it possible to all but eliminate the speed difference between
explicit and implicit --3x seems very high.

T.

Hmmm…another thing…passing prc to #explicit_blk as an lval rather
than invoking block_pass shaves another second off the time…

def explicit_blk(blk)
blk.call(“baz”)
end
n = 1_000_000
prc = lambda { | y | y }
Benchmark.bm(10) { | x |
x.report(“explicit”) { n.times { explicit_blk(prc) } }
}

=>

            user     system      total        real

explicit 5.030000 0.520000 5.550000 ( 5.774020)

…so I’m curious about two matters:

1.) Why does creating a Proc explicitly and passing it as a block_arg
rather than using a literal block (see previous post) speed up the
#explicit_blk benchmark 2 times, but doesn’t have very much effect the
#implicit_blk benchmark?

2.) Why is it less expensive to pass a Proc as an lval rather than as
a block_arg?

Anybody know?

Regards,
Jordan

On Dec 17, 2007, at 3:11 AM, Chiyuan Z. wrote:

def bar
foo { yield }
end

but that create another block, not the original one.

This is the only technique I’m aware of. I it
is still faster than explicitly reifying the outer block
before calling foo.

Somewhat related: Super will pass along an implicit
block. To disable this do:

super(a, b, &nil)

Gary W.

On Dec 17, 6:52 am, Trans [email protected] wrote:

def bar(&brk)

Do you mean, is there a keyword #block to go along with #block_given?
and #yield? As far as I know, there is no way to pass the block except
via an explicit reference.

But I think explicit may be the future. I’m pretty sure I’ve heard
some chatter about getting rid of #block_given? Technically I would
think it possible to all but eliminate the speed difference between
explicit and implicit --3x seems very high.

T.

On further testing it appears that in situations where can create a
proc and reuse it, the performance comes much closer (although the
implicit version says the same?!):

require “benchmark”
def implicit_blk
yield “baz”
end
def explicit_blk(&blk)
blk.call(“baz”)
end
n = 1_000_000
prc = lambda { | y | y }
Benchmark.bm(10) { | x |
x.report(“implicit”) { n.times { implicit_blk(&prc) } }
x.report(“explicit”) { n.times { explicit_blk(&prc) } }
}

=>

            user     system      total        real

implicit 3.730000 0.520000 4.250000 ( 4.479818)
explicit 6.000000 0.580000 6.580000 ( 6.763514)

…wonder why?

Regards,
Jordan

Hmm… what i’m looking for is just like super. As all you mentioned
above, maybe there’s no such feature yet. :slight_smile:

2007/12/18, Gary W. [email protected]:

On Dec 17, 7:49 pm, MonkeeSage [email protected] wrote:

#explicit_blk benchmark 2 times, but doesn’t have very much effect the
#implicit_blk benchmark?

2.) Why is it less expensive to pass a Proc as an lval rather than as
a block_arg?

Anybody know?

Regards,
Jordan

Bump

On Dec 17, 2007 9:11 AM, Chiyuan Z. [email protected] wrote:

def bar
foo { yield }
end

def bar
foo &Proc.new
end

HTH
Robert

http://ruby-smalltalk.blogspot.com/


All truth passes through three stages. First, it is ridiculed. Second,
it is violently opposed. Third, it is accepted as being self-evident.
Schopenhauer (attr.)

On Dec 21, 6:38 am, MonkeeSage [email protected] wrote:

n = 1_000_000
…so I’m curious about two matters:

Regards,
Jordan

Bump

Bump…anyone have any idea about the two questions I asked?

On Dec 24 2007, 4:47 pm, MonkeeSage [email protected] wrote:

blk.call(“baz”)
explicit 5.030000 0.520000 5.550000 ( 5.774020)

Anybody know?

Regards,
Jordan

Bump

Bump…anyone have any idea about the two questions I asked?

Bump again…

On 12/17/07, MonkeeSage [email protected] wrote:

}
#implicit_blk benchmark?
because you’ve moved the expensive proc creation outside of the
benchmark loop.

2.) Why is it less expensive to pass a Proc as an lval rather than as
a block_arg?

It’s not, actually the other way, only slightly:

require “benchmark”

def explicit_blk(blk)
blk.call(“baz”)
end
n = 1_000_000
prc = lambda { | y | y }
Benchmark.bm(10) { | x |
x.report(“outside”) { n.times { explicit_blk(prc) } }
x.report(“lval”) { n.times { prc = lambda { | y | y };
explicit_blk(prc) } }
x.report(“parm”) { n.times { explicit_blk(lambda { | y | y }) } }
}

            user     system      total        real

outside 1.430000 0.010000 1.440000 ( 1.558680)
lval 5.460000 0.030000 5.490000 ( 5.885967)
parm 5.320000 0.030000 5.350000 ( 5.748286)


Rick DeNatale

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

On Jan 14, 6:58 am, Rick DeNatale [email protected] wrote:

n = 1_000_000

1.) Why does creating a Proc explicitly and passing it as a block_arg
rather than using a literal block (see previous post) speed up the
#explicit_blk benchmark 2 times, but doesn’t have very much effect the
#implicit_blk benchmark?

because you’ve moved the expensive proc creation outside of the benchmark loop.

But that didn’t seem to make very much difference with the implicit
block using the yield keyword, Only with the explicit block passed via
formal parameter (see above). That’s the reason for my puzzlement –
creating the Proc outside the loop only seems to benefit when
explicitly passing it via formal parameter, but not when passing it
implicitly using the yield keyword. That seems strange to me.

2.) Why is it less expensive to pass a Proc as an lval rather than as
a block_arg?

It’s not, actually the other way, only slightly:

Err…I was referring to passing the object “prc” rather than the
reference “&prc”…the former being faster than the later. Still
curious about the reason for the difference in speed.

x.report(“parm”) { n.times { explicit_blk(lambda { | y | y }) } }

My blog on Rubyhttp://talklikeaduck.denhaven2.com/

Regards,
Jordan