liveBook · Manning

Yield

As explained in The Well-Grounded Rubyist, Fourth Edition

yield is a Ruby keyword that transfers execution to the block associated with the currently running method and then resumes the method afterward.

Start with `loop { puts "Looping forever!" }`. The braces supply a code block, and `loop` repeatedly runs it. Inside an iterator you write yourself, `yield` makes that handoff: execution moves from the running method to its block, then resumes in the method immediately after `yield`. The method has not returned. section 6.3.1 section 6.3.2

A small iterator

`def my_loop; yield while true; end` can be called as `my_loop { puts "My-looping forever!" }`. Each pass runs the block and returns control to `my_loop`, which yields again. A block belongs to the method call, but is separate from its argument list: a call can have arguments, a block, both, or neither. section 6.3.2 section 6.3.3

An iterator can pass values into its block. For example, `5.times { |i| puts i }` supplies `0` through `4` to `i`; the whole call returns `5`. This separates two events that are easy to confuse: one method invocation can yield many times, but returns once when it finishes. Without an attached block, a method has nothing to yield to. section 6.3.5 section 6.3.3

Listing 6.4 yield at work in Integer#my_times
class Integer
  def my_times
    c = 0
    puts "c = 0"
    puts "until c == #{self}..."        1
    until c == self
      yield c
      c += 1
    end
    self               2
  end
end
result = 5.my_times {|i| puts "I'm on iteration #{i}!" }
puts result

Follow `my_times` through one pass: `yield c` gives the current count to the block; when the block finishes, `c += 1` runs. After the loop, `self` makes the integer receiver the method’s return value. section 6.3.5

Values travel back the other way, too: an expression such as `acc << yield(self[c])` appends the block’s result to an array. That is the key distinction between `each`, which returns its receiver, and `map`, which collects block results into a new array. A custom `my_map` can use `yield` directly or build on `my_each`. section 6.3.7

Yielding also works outside ordinary iteration. A `BasicObject` subclass can use `method_missing` to build an indented list, yielding to nested blocks as it increases the indentation level and continuing afterward to decrease it. When the block is optional, that implementation checks for one before yielding; `BasicObject` does not provide `block_given?`. section 13.3.2

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Works through repeated yielding, values passed to blocks, block results, and method returns using custom iterator implementations.
Examples
Uses `my_loop`, `Integer#my_times`, `Array#my_map`, and an indented-list generator to show successive uses of `yield`.
What it assumes
Assumes familiarity with method calls and loops while introducing the distinction between a call’s arguments and its block.
What you can do after
Build it from scratch: write iterators that pass values to blocks, collect their results, and choose a method return value.
How it connects
Connects code blocks and method calls to iterators, `each`, `map`, and `method_missing`.

Also explained in

Compare how 10 books explain yield →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.