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 Fischer <ronald.fischer@venyon.com>
Phone: +49-89-452133-162

Ronald Fischer 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.

···

--
  Phlip
  Test Driven Ajax (on Rails) [Book]
  "Test Driven Ajax (on Rails)"
  assert_xpath, assert_javascript, & assert_ajax

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 06/08/07, Ronald Fischer <ronald.fischer@venyon.com> wrote:

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 Fischer <ronald.fischer@venyon.com>
Phone: +49-89-452133-162

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

···

On Monday 06 August 2007, Ronald Fischer wrote:

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

Hi --

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?

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, Ronald Fischer wrote:

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

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:in `bar'
        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.

···

On 8/6/07, Ronald Fischer <ronald.fischer@venyon.com> wrote:

> 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

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

···

On 8/6/07, Sylvain Joyeux <sylvain.joyeux@polytechnique.org> wrote:

On Monday 06 August 2007, Ronald Fischer wrote:

Hi --

···

On Mon, 6 Aug 2007, Phlip wrote:

Ronald Fischer 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.

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

David

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

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

David

···

On Mon, 6 Aug 2007, dblack@rubypal.com wrote:

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

--
* Books:
   RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
   RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
     & consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

> 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

Ronald Fischer 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 <phlip2005@gmail.com> wrote:

--
  Phlip
  Test Driven Ajax (on Rails) [Book]
  "Test Driven Ajax (on Rails)"
  assert_xpath, assert_javascript, & assert_ajax

--
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

Ronald Fischer 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 8/6/07, Phlip <phlip2005@gmail.com> wrote:

--
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

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

···

2007/8/6, Phlip <phlip2005@gmail.com>:

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.

Ronald Fischer 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 8/6/07, Phlip <phlip2005@gmail.com> wrote:

--
[...] as simple as possible, but no simpler.
-- Attributed to Albert Einstein

Sorry, this was not intentional...

J.

···

On 8/6/07, Jano Svitok <jan.svitok@gmail.com> wrote:

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 Aug 6, 5:02 am, dbl...@rubypal.com wrote:

Hi --

On Mon, 6 Aug 2007, Phlip wrote:
> Ronald Fischer 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.

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

Pit Capitain wrote:

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

What if the block were optional?

(I forgot to mention that's typical of API-style code...)

···

--
Phlip
Test Driven Ajax (on Rails) [Book]
^ assert_xpath
http://tinyurl.com/yrc77g <-- assert_latest Model

I actually wanted to say something about this issue but it seems that
my posts got cut, not sent, whatever, even I have difficulties to
understand the fragments.
Please (1) ignore them, (2) excuse me for the noise and (3) blame gmail ;).

Sorry
Robert

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

James Edward Gray II

···

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

Pit Capitain wrote:

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.

What if the block were optional?

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

···

2007/8/6, James Edward Gray II <james@grayproductions.net>:

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.