Using yield

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

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

···

On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk <joe.vandyk@boeing.com> wrote:

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 [i][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

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: dga@lcs.mit.edu me: dga@pobox.com
      MIT Laboratory for Computer Science http://www.angio.net/

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

···

On Sat, 4 Dec 2004 09:32:39 +0900 "Joe Van Dyk" <joe.vandyk@boeing.com> 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

--
Brian Schröder
http://ruby.brian-schroeder.de/quiz/crossword/ (Spoiler)

"Joe Van Dyk" <joe.vandyk@boeing.com> schrieb im Newsbeitrag news:I868Ho.73v@news.boeing.com...

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

Hi --

···

On Sat, 4 Dec 2004, Sam Stephenson wrote:

On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk <joe.vandyk@boeing.com> 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
dblack@wobblini.net

Sam Stephenson wrote:

···

On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk > <joe.vandyk@boeing.com> 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

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" <joe.vandyk@boeing.com> 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 :slight_smile:

David

--
David A. Black
dblack@wobblini.net

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.

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.

Joe Van Dyk ha scritto:

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

···

On Sat, 4 Dec 2004 09:32:39 +0900, Joe Van Dyk >><joe.vandyk@boeing.com> wrote:

Hi,

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

···

From: "Joe Van Dyk" <joe.vandyk@boeing.com>

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

Regards,

Brian

···

On Sun, 5 Dec 2004 05:37:26 +0900 "David A. Black" <dblack@wobblini.net> 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" <joe.vandyk@boeing.com> 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 :slight_smile:

--
Brian Schröder
http://www.brian-schroeder.de/

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
dblack@wobblini.net

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

···

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

--
-- Jim Weirich jim@weirichhouse.org 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)

Hi --

> Hi --
>
>
> >
> > > 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 :slight_smile:
>
>

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

···

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

On Sun, 5 Dec 2004 05:37:26 +0900 > "David A. Black" <dblack@wobblini.net> wrote:
> On Sun, 5 Dec 2004, Brian [ISO-8859-15] Schröder wrote:
> > On Sat, 4 Dec 2004 09:32:39 +0900 > > > "Joe Van Dyk" <joe.vandyk@boeing.com> wrote:

--
David A. Black
dblack@wobblini.net

"David A. Black" <dblack@wobblini.net> schrieb im Newsbeitrag
news:Pine.LNX.4.44.0412051338420.27774-100000@wobblini...

Hi --

> 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

···

On Mon, 6 Dec 2004, Florian Gross wrote:

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

···

From: "Jim Weirich" <jim@weirichhouse.org>

Hi --

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

···

On Tue, 7 Dec 2004, Robert Klemme wrote:

--
David A. Black
dblack@wobblini.net