Using yield

Discussion in 'Ruby' started by Joe Van Dyk, Dec 4, 2004.

  1. Joe Van Dyk

    Joe Van Dyk Guest

    I come from a heavy C++ background, discovered Ruby a few months ago and
    love it.

    I've found that using blocks is a very natural thing. However, I have not
    once used 'yield'. I'm sure that there are events when using yield would be
    helpful, but I have no clue when it would be appropriate to use.

    Thoughts? When do you use the 'yield' statement in code?

    Joe
    Joe Van Dyk, Dec 4, 2004
    #1
    1. Advertising

  2. On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk <> wrote:
    > When do you use the 'yield' statement in code?


    When you want to write methods that take blocks.

    | def repeatedly_write(times, &block)
    | times.times do |i|
    | puts yield(i)
    | end
    | end
    |
    | repeatedly_write(5) do |i|
    | "iteration #{i}"
    | end

    prints:
    iteration 0
    iteration 1
    iteration 2
    iteration 3
    iteration 4

    In this example, ``yield(i)'' and ``block.call(i)'' are equivalent.

    > Joe


    Sam
    Sam Stephenson, Dec 4, 2004
    #2
    1. Advertising

  3. Joe Van Dyk

    Tim Hunter Guest

    Joe Van Dyk wrote:

    > I come from a heavy C++ background, discovered Ruby a few months ago and
    > love it.
    >
    > I've found that using blocks is a very natural thing. However, I have not
    > once used 'yield'. I'm sure that there are events when using yield would
    > be helpful, but I have no clue when it would be appropriate to use.
    >
    > Thoughts? When do you use the 'yield' statement in code?
    >
    > Joe


    I use it with methods that create resources that need to be cleaned up
    after, the way File.open closes the file for you after the block
    terminates. If you're coming from C++, think destructors.

    Here's an example from RMagick. The Image#view method extracts a rectangle
    of pixels from an image and yields to a block (if present). Within the
    block you can address the pixels using [j] indexes. When the block ends,
    if any of the pixels have been modified all the pixels are stored
    ("sync'd") back to the image. The code looks like this:

    def view(x, y, width, height)
    view = View.new(self, x, y, width, height)
    if block_given?
    begin
    yield(view)
    ensure
    view.sync
    end
    return nil
    else
    return view
    end
    end

    You use #view like this:

    image.view(5, 10, 20, 20) do |view|
    view[5][7] = 'yellow'
    # other useful stuff...
    end
    Tim Hunter, Dec 4, 2004
    #3
  4. Hi --

    On Sat, 4 Dec 2004, Sam Stephenson wrote:

    > On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk <> wrote:
    > > When do you use the 'yield' statement in code?

    >
    > When you want to write methods that take blocks.
    >
    > | def repeatedly_write(times, &block)


    You don't need &block there, since you don't use the block directly
    (you just yield to it).


    David

    --
    David A. Black
    David A. Black, Dec 4, 2004
    #4
  5. On Sat, Dec 04, 2004 at 09:32:39AM +0900, Joe Van Dyk scribed:
    > I come from a heavy C++ background, discovered Ruby a few months ago and
    > love it.
    >
    > I've found that using blocks is a very natural thing. However, I have not
    > once used 'yield'. I'm sure that there are events when using yield would be
    > helpful, but I have no clue when it would be appropriate to use.
    >
    > Thoughts? When do you use the 'yield' statement in code?


    I use it to pass in an additional filtering routine to
    a database selection class. The selection thing knows some
    basic stuff like time, but if you want to filter
    more precisely,
    you can pass it a block:

    db_generator = new thingy(start_time, end_time) { |x|
    x.attr1 == "frog" && x.attr2 >= 5 }


    and then in later code you can grab stuff from the generator
    and it's filtered in the way you specified.

    -Dave
    --
    work: me:
    MIT Laboratory for Computer Science http://www.angio.net/
    David G. Andersen, Dec 4, 2004
    #5
  6. Joe Van Dyk

    Joe Van Dyk Guest

    Sam Stephenson wrote:
    > On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk
    > <> wrote:
    >> When do you use the 'yield' statement in code?

    >
    > When you want to write methods that take blocks.


    Yes. What types of methods generally should take blocks?

    Joe
    Joe Van Dyk, Dec 4, 2004
    #6
  7. Joe Van Dyk ha scritto:
    > Sam Stephenson wrote:
    >
    >>On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk
    >><> wrote:
    >>
    >>>When do you use the 'yield' statement in code?

    >>
    >>When you want to write methods that take blocks.

    >
    >
    > Yes. What types of methods generally should take blocks?
    >


    My little list:
    [1] those when behaviour can be further specified.
    i.e. #sort and #sort_by can get a block to specify how to sort an object

    [2] those where a resource could be freed
    i.e. constructors like File.new or Socket.new get a block so that the
    undelying resource would be freed when the block ends instead of waiting
    for the gc.

    [3] those where one would like to lazyly use/reuse a snippet of code
    given from the user

    i.e. set_trace_func

    There are surely others, the best way to get the felling is probably
    looking at existing ruby code.
    gabriele renzi, Dec 4, 2004
    #7
  8. On Sat, 4 Dec 2004 09:32:39 +0900
    "Joe Van Dyk" <> wrote:

    > I come from a heavy C++ background, discovered Ruby a few months ago and
    > love it.
    >
    > I've found that using blocks is a very natural thing. However, I have not
    > once used 'yield'. I'm sure that there are events when using yield would be
    > helpful, but I have no clue when it would be appropriate to use.
    >
    > Thoughts? When do you use the 'yield' statement in code?
    >
    > Joe


    Yield is just a shortcut for block.call.

    If I am Lazy, and I don't need to pass the block further I use yield. But I
    believe that normally using block.call is more explicit and therefore
    preferable.

    It may be the case that block.call has a small performance penalty compared
    with yield because the block needs to get bound to a variable and therefore be
    turned into an object.

    Regards,

    Brian


    --
    Brian Schröder
    http://ruby.brian-schroeder.de/quiz/crossword/ (Spoiler)
    Brian Schröder, Dec 4, 2004
    #8
  9. Hi --

    On Sun, 5 Dec 2004, Brian [ISO-8859-15] Schröder wrote:

    > On Sat, 4 Dec 2004 09:32:39 +0900
    > "Joe Van Dyk" <> wrote:
    >
    > > I come from a heavy C++ background, discovered Ruby a few months ago and
    > > love it.
    > >
    > > I've found that using blocks is a very natural thing. However, I have not
    > > once used 'yield'. I'm sure that there are events when using yield would be
    > > helpful, but I have no clue when it would be appropriate to use.
    > >
    > > Thoughts? When do you use the 'yield' statement in code?
    > >
    > > Joe

    >
    > Yield is just a shortcut for block.call.
    >
    > If I am Lazy, and I don't need to pass the block further I use yield. But I
    > believe that normally using block.call is more explicit and therefore
    > preferable.


    'yield' is equally explicit, and equally unambiguous. It tells you
    exactly as much as block.call does. I wouldn't worry about the
    laziness part of it; if you measure laziness by power per word of
    code, all Ruby programmers are already massively lazy :)


    David

    --
    David A. Black
    David A. Black, Dec 4, 2004
    #9
  10. Brian Schröder wrote:
    > Yield is just a shortcut for block.call.


    Yield has an advantage: rdoc can recognize it and generate docs for it,
    including the names of the variables that are yielded to the block.

    The speed advnatage of yield can also be significant, IMHO.
    Joel VanderWerf, Dec 4, 2004
    #10
  11. Joe Van Dyk

    Bill Kelly Guest

    Hi,

    From: "Joe Van Dyk" <>
    >
    > What types of methods generally should take blocks?


    My most recent use of yield is in a tree-structured database,
    where I wanted to be able to perform {some operation} on a
    node and all its children. So,

    def apply_all(&block)
    yield self
    @children.each_value {|n| n.apply_all(&block) } if @children
    end

    The above is a method of the database node class. It
    yields itself, and recursively calls apply_all on all of
    its children, so they can yield themselves, etc....
    So I can use it like:

    some_node.apply_all {|n| n.some_method(foo) }

    ...to call some_method on some_node and all of its children.



    My second most recent use of yield was to do some deferred
    processing.

    @server.rcon_cmd("dmflags #{dmflags}") do |resp|
    @server_state['dmflags'] = dmflags.to_s if resp
    end

    The above wants to send a command to a server, and when the
    response is later received, the block is called to perform
    some further processing.

    The command gets queued and is processed on different
    thread. The block, above, is also passed along...
    So that, eventually, when the command has been sent to
    the server and the server's response has been received,
    the block will be called and passed the server's response
    as its argument.

    I was particularly thrilled with Ruby when writing this,
    because originally my code had been written to NOT queue
    the commands to the server, but to send the command
    immediately and do a blocking wait for the reply... Like,

    if resp = @server.rcon_cmd("dmflags #{dmflags}")
    @server_state['dmflags'] = dmflags.to_s
    end

    So I already had a bunch of code like the above, before I
    realized that I really wanted to queue the commands and
    process their result later. And you can see how little
    I needed to change my code to make that happen!


    Hope this helps, just a couple ways I've used yield recently.


    Regards,

    Bill
    Bill Kelly, Dec 4, 2004
    #11
  12. Joe Van Dyk

    Jim Weirich Guest

    On Saturday 04 December 2004 05:44 pm, Bill Kelly wrote:
    > My most recent use of yield is in a tree-structured database,
    > where I wanted to be able to perform {some operation} on a
    > node and all its children.  So,
    >
    >   def apply_all(&block)
    >     yield self
    >     @children.each_value {|n| n.apply_all(&block) } if @children
    >   end


    This is a very common use of blocks. You might consider the following
    modification, it may (or may not) be useful in your application.

    Change the name of "apply_all" to "each", and then include the module
    Enumerable into your class. Then you can do things like (assuming "name"
    might be a method on your node) ....

    some_node.collect { |n| n.name } # Get a list of all the names
    some_node.find { |n| n.name =~ /^Bill/ } # Find a matching node

    --
    -- Jim Weirich http://onestepback.org
    -----------------------------------------------------------------
    "Beware of bugs in the above code; I have only proved it correct,
    not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
    Jim Weirich, Dec 5, 2004
    #12
  13. Joe Van Dyk

    Bill Kelly Guest

    From: "Jim Weirich" <>
    > Change the name of "apply_all" to "each", and then include the module
    > Enumerable into your class. Then you can do things like (assuming "name"
    > might be a method on your node) ....
    >
    > some_node.collect { |n| n.name } # Get a list of all the names
    > some_node.find { |n| n.name =~ /^Bill/ } # Find a matching node


    Nice, thanks !!


    Regards,

    Bill
    Bill Kelly, Dec 5, 2004
    #13
  14. "Joe Van Dyk" <> schrieb im Newsbeitrag
    news:...
    >I come from a heavy C++ background, discovered Ruby a few months ago and
    > love it.
    >
    > I've found that using blocks is a very natural thing. However, I have not
    > once used 'yield'. I'm sure that there are events when using yield would
    > be
    > helpful, but I have no clue when it would be appropriate to use.
    >
    > Thoughts? When do you use the 'yield' statement in code?


    When implementing Enumerable classes

    class Endless
    include Enumerable
    def each
    i = 0
    loop do
    yield i
    i += 1
    end
    end
    end

    More generally when you don't need direct access to the block given and when
    you don't need to forward it to another method call. I think yield is
    faster than the block form also.

    Regards

    robert
    Robert Klemme, Dec 5, 2004
    #14
  15. Robert Klemme wrote:

    >> Thoughts? When do you use the 'yield' statement in code?

    > More generally when you don't need direct access to the block given and
    > when you don't need to forward it to another method call. I think yield
    > is faster than the block form also.


    But note that you can also forward blocks without using the &block syntax:

    irb(main):022:0> def five_times
    irb(main):023:1> 5.times { |index| yield index }
    irb(main):024:1> end
    => nil
    irb(main):025:0> five_times { |i| puts "Hello ##{i}" }
    Hello #0
    Hello #1
    Hello #2
    Hello #3
    Hello #4

    I'd expect this to be slower than the &block syntax, but I have not
    benchmarked it. Maybe the &block syntax is also less clutter to look at
    and thus easier to understand.
    Florian Gross, Dec 5, 2004
    #15
  16. On Sun, 5 Dec 2004 05:37:26 +0900
    "David A. Black" <> wrote:

    > Hi --
    >
    > On Sun, 5 Dec 2004, Brian [ISO-8859-15] Schröder wrote:
    >
    > > On Sat, 4 Dec 2004 09:32:39 +0900
    > > "Joe Van Dyk" <> wrote:
    > >
    > > > I come from a heavy C++ background, discovered Ruby a few months ago and
    > > > love it.
    > > >
    > > > I've found that using blocks is a very natural thing. However, I have
    > > > not once used 'yield'. I'm sure that there are events when using yield
    > > > would be helpful, but I have no clue when it would be appropriate to use.
    > > >
    > > > Thoughts? When do you use the 'yield' statement in code?
    > > >
    > > > Joe

    > >
    > > Yield is just a shortcut for block.call.
    > >
    > > If I am Lazy, and I don't need to pass the block further I use yield. But I
    > > believe that normally using block.call is more explicit and therefore
    > > preferable.

    >
    > 'yield' is equally explicit, and equally unambiguous. It tells you
    > exactly as much as block.call does. I wouldn't worry about the
    > laziness part of it; if you measure laziness by power per word of
    > code, all Ruby programmers are already massively lazy :)
    >
    >


    I see it as not as explicit, as it does not document in the method signature
    that the message takes a block.

    Regards,

    Brian


    --
    Brian Schröder
    http://www.brian-schroeder.de/
    Brian Schröder, Dec 5, 2004
    #16
  17. Hi --

    On Mon, 6 Dec 2004, Florian Gross wrote:

    > Robert Klemme wrote:
    >
    > >> Thoughts? When do you use the 'yield' statement in code?

    > > More generally when you don't need direct access to the block given and
    > > when you don't need to forward it to another method call. I think yield
    > > is faster than the block form also.

    >
    > But note that you can also forward blocks without using the &block syntax:
    >
    > irb(main):022:0> def five_times
    > irb(main):023:1> 5.times { |index| yield index }
    > irb(main):024:1> end
    > => nil
    > irb(main):025:0> five_times { |i| puts "Hello ##{i}" }
    > Hello #0
    > Hello #1
    > Hello #2
    > Hello #3
    > Hello #4
    >
    > I'd expect this to be slower than the &block syntax, but I have not
    > benchmarked it. Maybe the &block syntax is also less clutter to look at
    > and thus easier to understand.


    Wouldn't the &block form be more clutter? Well, not that it's so
    much clutter in either case, but I think it would be slightly wordier
    (def five_time(&block) etc.)


    David

    --
    David A. Black
    David A. Black, Dec 5, 2004
    #17
  18. Hi --

    On Mon, 6 Dec 2004, Brian [ISO-8859-15] Schröder wrote:

    > On Sun, 5 Dec 2004 05:37:26 +0900
    > "David A. Black" <> wrote:
    >
    > > Hi --
    > >
    > > On Sun, 5 Dec 2004, Brian [ISO-8859-15] Schröder wrote:
    > >
    > > > On Sat, 4 Dec 2004 09:32:39 +0900
    > > > "Joe Van Dyk" <> wrote:
    > > >
    > > > > I come from a heavy C++ background, discovered Ruby a few months ago and
    > > > > love it.
    > > > >
    > > > > I've found that using blocks is a very natural thing. However, I have
    > > > > not once used 'yield'. I'm sure that there are events when using yield
    > > > > would be helpful, but I have no clue when it would be appropriate to use.
    > > > >
    > > > > Thoughts? When do you use the 'yield' statement in code?
    > > > >
    > > > > Joe
    > > >
    > > > Yield is just a shortcut for block.call.
    > > >
    > > > If I am Lazy, and I don't need to pass the block further I use yield. But I
    > > > believe that normally using block.call is more explicit and therefore
    > > > preferable.

    > >
    > > 'yield' is equally explicit, and equally unambiguous. It tells you
    > > exactly as much as block.call does. I wouldn't worry about the
    > > laziness part of it; if you measure laziness by power per word of
    > > code, all Ruby programmers are already massively lazy :)
    > >
    > >

    >
    > I see it as not as explicit, as it does not document in the method signature
    > that the message takes a block.


    That actually doesn't tell you much, though, in practical terms. Any
    method can have a &block argument, whether it calls it or not -- but,
    more importantly, the presence of a &block argument doesn't tell you
    what the block actually does. So its value as documentation is
    somewhat limited; you still have to either read the code or the
    documentation before you can call the method properly.


    David

    --
    David A. Black
    David A. Black, Dec 6, 2004
    #18
  19. "David A. Black" <> schrieb im Newsbeitrag
    news:pine.LNX.4.44.0412051338420.27774-100000@wobblini...
    > Hi --
    >
    > On Mon, 6 Dec 2004, Florian Gross wrote:
    >
    > > Robert Klemme wrote:
    > >
    > > >> Thoughts? When do you use the 'yield' statement in code?
    > > > More generally when you don't need direct access to the block given

    and
    > > > when you don't need to forward it to another method call. I think

    yield
    > > > is faster than the block form also.

    > >
    > > But note that you can also forward blocks without using the &block

    syntax:
    > >
    > > irb(main):022:0> def five_times
    > > irb(main):023:1> 5.times { |index| yield index }
    > > irb(main):024:1> end
    > > => nil
    > > irb(main):025:0> five_times { |i| puts "Hello ##{i}" }
    > > Hello #0
    > > Hello #1
    > > Hello #2
    > > Hello #3
    > > Hello #4
    > >
    > > I'd expect this to be slower than the &block syntax, but I have not
    > > benchmarked it. Maybe the &block syntax is also less clutter to look

    at
    > > and thus easier to understand.


    13:21:36 [robert.klemme]: ruby yield-vs-block.rb
    user system total real
    yield 0.250000 0.000000 0.250000 ( 0.249000)
    block 0.125000 0.000000 0.125000 ( 0.124000)
    13:21:44 [robert.klemme]: cat yield-vs-block.rb

    require 'benchmark'
    include Benchmark

    REP = 100000

    def bl_yield(n)
    n.times {|i| yield i}
    end

    def bl_fwd(n,&b)
    n.times(&b)
    end

    bm(20) do |b|
    b.report("yield") do
    bl_yield(REP) {|i| i + 1}
    end

    b.report("block") do
    bl_fwd(REP) {|i| i + 1}
    end
    end

    I blieve the yield forwarding is slower because there is one more call.

    > Wouldn't the &block form be more clutter? Well, not that it's so
    > much clutter in either case, but I think it would be slightly wordier
    > (def five_time(&block) etc.)


    For forwarding I prefer &b because the original block is simply passed on
    vs. a new block yields to the original block. That seems awkward to me
    and seems to be slower, too. Personally I find the yield forwarding more
    clutter. YMMV

    Kind regards

    robert
    Robert Klemme, Dec 7, 2004
    #19
  20. Hi --

    On Tue, 7 Dec 2004, Robert Klemme wrote:

    > 13:21:36 [robert.klemme]: ruby yield-vs-block.rb
    > user system total real
    > yield 0.250000 0.000000 0.250000 ( 0.249000)
    > block 0.125000 0.000000 0.125000 ( 0.124000)
    > 13:21:44 [robert.klemme]: cat yield-vs-block.rb
    >
    > require 'benchmark'
    > include Benchmark
    >
    > REP = 100000
    >
    > def bl_yield(n)
    > n.times {|i| yield i}
    > end
    >
    > def bl_fwd(n,&b)
    > n.times(&b)
    > end


    Those aren't equivalent, though. The second one would have to be:

    n.times {|i| b.call(i) }

    to compare the two idioms directly.

    When I make that change I get:

    yield 0.320000 0.000000 0.320000 ( 0.332194)
    block 0.460000 0.000000 0.460000 ( 0.490299)


    > I blieve the yield forwarding is slower because there is one more call.
    >
    > > Wouldn't the &block form be more clutter? Well, not that it's so
    > > much clutter in either case, but I think it would be slightly wordier
    > > (def five_time(&block) etc.)

    >
    > For forwarding I prefer &b because the original block is simply passed on
    > vs. a new block yields to the original block. That seems awkward to me
    > and seems to be slower, too. Personally I find the yield forwarding more
    > clutter. YMMV


    The clutter point was (at least in my mind :) strictly about the
    difference between:

    def x
    yield
    end

    and

    def x(&b)
    b.call
    end

    As for forwarding a block to a new method -- isn't &b the only way?
    Or am I behind the times on automatic propagation? (But even in that
    case I don't think supplying block #1 to method #2 is the same as
    yielding to block #1 during method #1.)


    David

    --
    David A. Black
    David A. Black, Dec 7, 2004
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    1
    Views:
    320
    Gabriel Genellina
    Apr 22, 2008
  2. Paul
    Replies:
    5
    Views:
    125
    Robert Klemme
    Jul 17, 2003
  3. Markus
    Replies:
    1
    Views:
    195
    Mark Hubbart
    Sep 27, 2004
  4. Alber Eric

    using Proc and yield

    Alber Eric, Dec 15, 2006, in forum: Ruby
    Replies:
    4
    Views:
    134
    George Ogata
    Dec 16, 2006
  5. Michael Edgar
    Replies:
    13
    Views:
    271
    Brian Candler
    Apr 21, 2011
Loading...

Share This Page