Yield or call?

def f(&b)

b.call

end

def g

yield b

end

As far I understood the documentation for call and yield, both are
equivalent:

f { … }
g { … }

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

Ronald

Ronald F. wrote:

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

I am learning to consider ‘yield’ as a fossil of an early Ruby that
could
not treat the bound block as a variable. I only use ‘yield’ as a slight
convenience - a few less characters to type - in application-specific
code.

When writing API-style code, I always start with &block because it’s
only a
matter of time before I refactor the code and start passing that &block
into
a helper method.

Watch out there, “yield b” isn’t the same as “b.call”, you’re probably
aware
of this, but from your example one could get confused with your reuse of
the
variable ‘b’. I believe the general consensus is that unless you need to
do
something special with the block, i.e foo.instance_eval(&block), then
just
use yield. It’s certainly much cleaner to read than taking &block as a
parameter all over the place just for the sake of using .call.

On 8/6/07, Sylvain J. [email protected] wrote:

Sorry, this was not intentional…

J.

On Monday 06 August 2007, Ronald F. wrote:

end
Ronald
There is a difference in object allocation. Ruby allocates 1 object for
each function call, one more in the case of the &b form (it has to
allocate the Proc).

Then, yield costs only one object while Proc#call costs two. It can make
a
difference in case of large iterations, if you’re concerned (like I am)
about the GC eating your time.

Sylvain

Hi –

On Mon, 6 Aug 2007, Phlip wrote:

matter of time before I refactor the code and start passing that &block into
a helper method.

I think that’s premature pessimization :slight_smile: See my other post for some
benchmarks on yield vs. capture-and-call.

David

Hi –

On Mon, 6 Aug 2007, Ronald F. wrote:

end

As far I understood the documentation for call and yield, both are
equivalent:

f { … }
g { … }

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

I think you mean just yield (not yield b).

yield is a lot faster:

david-a-blacks-computer:~/hacking dblack$ ruby yi.rb

require ‘benchmark’
include Benchmark

def x(&b)
b.call
end

def y
yield
end

n = 1000000

bmbm do |b|
b.report(“b”) { n.times { x {} } }
b.report(“y”) { n.times { y {} } }
end

Rehearsal -------------------------------------
b 3.760000 0.010000 3.770000 ( 3.770292)
y 0.590000 0.000000 0.590000 ( 0.595891)
---------------------------- total: 4.360000sec

     user     system      total        real

b 3.780000 0.000000 3.780000 ( 3.784505)
y 0.610000 0.000000 0.610000 ( 0.609034)

So I’d only use the &b/call version if you really need the thing as an
object. I also consider yield more idiomatic, or something… since
the whole anatomy of the method call is designed to provide the extra
component (the code block). When you capture the block as a proc,
you’re capturing a syntactic construct as an object – sort of like:

def x %arg_list # imaginary example

where arg_list was an ArgumentList object. That’s logically secondary
to the presence of the argument list in the first place, and similarly
the block exists prior to, and independently of, the fact that the
language lets you capture it in a variable.

David

On Mon, 6 Aug 2007, [email protected] wrote:

david-a-blacks-computer:~/hacking dblack$ ruby yi.rb

Whoops, that was supposed to be cat yi.rb, followed by ruby yi.rb. (A
cut-and-paste accident :slight_smile:

David

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

I think you mean just yield (not yield b).

Correct!

yield is a lot faster:

Thank you (and also to all the others) for the clarification.

Ronald

On 8/6/07, Phlip [email protected] wrote:

Ronald F. wrote:

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

I am learning to consider ‘yield’ as a fossil of an early Ruby that could
not treat the bound block as a variable. I only use ‘yield’ as a slight
convenience - a few less characters to type - in application-specific code.
Do not do this, yield suffers a lot from a bad reputation it does not
deserve, see also David’s benchmarks above.

When writing API-style code, I always start with &block because it’s only a
matter of time before I refactor the code and start passing that &block into
a helper method.
Why? I do not think that this is necessary.
Just replace the refactoring
old: yield ==> something &blk

On 8/6/07, Phlip [email protected] wrote:

Ronald F. wrote:

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

I am learning to consider ‘yield’ as a fossil of an early Ruby that could
not treat the bound block as a variable. I only use ‘yield’ as a slight
convenience - a few less characters to type - in application-specific code.
Do not do this, yield suffers a lot from a bad reputation it does not
deserve, see also David’s benchmarks above.

When writing API-style code, I always start with &block because it’s only a
matter of time before I refactor the code and start passing that &block into
a helper method.
Why? I do not think that this is necessary.
Just replace the refactoring
old: yield ==> something &blk + changing the def
with
new: yield ==> something &Proc.new

However I never use yield, but for a completely different reason, I
want my def to show if I yield or not.
In case I am unhappy with performance I can still change back.

Cheers
Robert

On Aug 6, 5:02 am, [email protected] wrote:

convenience - a few less characters to type - in application-specific code.

When writing API-style code, I always start with &block because it’s only a
matter of time before I refactor the code and start passing that &block into
a helper method.

I think that’s premature pessimization :slight_smile: See my other post for some
benchmarks on yield vs. capture-and-call.

Is there no way for Ruby to optimize in the &block case? After all,
they are functionally equivalent if you only use #call on the block.

T.

On 8/6/07, Ronald F. [email protected] wrote:

Is there a principal reason when to prefer call over yield (or vice
versa), or are these only syntactic variations of the same feature?

In addition to what others have said (especially David Black), they
throw different errors.

def foo
yield
end
=> nil

foo
LocalJumpError: no block given
from (irb):2:in `foo’
from (irb):4

def bar(&block)
block.call
end
=> nil

bar
NoMethodError: undefined method call' for nil:NilClass from (irb):6:inbar’
from (irb):8

I also consider yield() to be more idiomatic unless you need to
manipulate or pass along the proc object to another method.

2007/8/6, Phlip [email protected]:

When writing API-style code, I always start with &block because it’s only a
matter of time before I refactor the code and start passing that &block into
a helper method.

Phlip, you can do the equivalent with yield:

def x(&b); xx(&b); end
def xx(&b); b.call; end

vs.

def y; yy { yield }; end
def yy; yield; end

Also in this case the yield version is much faster.

Regards,
Pit

On Aug 6, 2007, at 10:39 AM, Phlip wrote:

def x(&b); xx(&b); end
def xx(&b); b.call; end

vs.

def y; yy { yield }; end
def yy; yield; end

Also in this case the yield version is much faster.

What if the block were optional?

You can use block_given? to find out if a block was provided.

James Edward G. II

Pit C. wrote:

def y; yy { yield }; end
def yy; yield; end

Also in this case the yield version is much faster.

What if the block were optional?

(I forgot to mention that’s typical of API-style code…)

2007/8/6, James Edward G. II [email protected]:

On Aug 6, 2007, at 10:39 AM, Phlip wrote:

What if the block were optional?

You can use block_given? to find out if a block was provided.

Yes, but not in the helper method. In the code I’ve shown there’s
always a block passed to the helper method. Phlip has a point here.

Regards,
Pit

On Tue, 2007-08-07 at 01:38 +0900, Pit C. wrote:

2007/8/6, James Edward G. II [email protected]:

On Aug 6, 2007, at 10:39 AM, Phlip wrote:

What if the block were optional?

You can use block_given? to find out if a block was provided.

Yes, but not in the helper method. In the code I’ve shown there’s
always a block passed to the helper method. Phlip has a point here.

That’s very easy to solve:

def x
if block_given?
y { yield }
else
y
end
end

def y
if block_given?
yield
else
“foo”
end
end

x #=> “foo”
x { “bar” } #=> “bar”

Cheers,
Daniel S.

Hi –

On Tue, 7 Aug 2007, Pit C. wrote:

2007/8/6, James Edward G. II [email protected]:

On Aug 6, 2007, at 10:39 AM, Phlip wrote:

What if the block were optional?

You can use block_given? to find out if a block was provided.

Yes, but not in the helper method. In the code I’ve shown there’s
always a block passed to the helper method. Phlip has a point here.

I still wouldn’t use block.call automatically. I’d stick to yield
until it becomes necessary to wrap it in the slower construct.

David