Skip to content

Instantly share code, notes, and snippets.

@damncabbage
Last active July 19, 2019 03:01
Show Gist options
  • Save damncabbage/47bbd7777da617d959c8d22c2dbf8bf6 to your computer and use it in GitHub Desktop.
Save damncabbage/47bbd7777da617d959c8d22c2dbf8bf6 to your computer and use it in GitHub Desktop.
Explaining Ruby Yield

Yields control back to the context that resumed the fiber ah yeah totally :thinking_very_much: ... anyone have an english explanation of ruby yield I never get it. Also yield_self and the difference please, thanks.

There's unfortunately a few things going on; there's regular Ruby yield keyword, there's yield_self method on everything, and there's the Fiber version of yield that has nothing to do with either (which basically nobody is going to need to know about, including me).

Which did you want to know about? 'Regular' yield?


Just in case this helps:

def greet(place)
  name = yield if block_given?
  puts "Welcome to #{place}, #{name}."
end

greet("Hell") do
  "Frank"
end

# prints out "Welcome to Hell, Frank."

and

def greet(place, &block)
  name = block.call() if block
  puts "Welcome to #{place}, #{name}."
end

greet("Hell") do
  "Frank"
end

# prints out "Welcome to Hell, Frank."

... are the same thing.

You can think of it as:

  • A block do |x| ... end / { |x| ... } is like a little function.
  • Every method in Ruby can take up to one of these functions on the end.
  • You can call this function by having a &-d parameter, eg. &block, &get_name, etc. OR
  • You can call this function by using yield. There's only ever going to be one function, so it knows what to call.
def add_one_then_do_something_then_double(starting_number)
  starting_plus_one = starting_number + 1
  transformed_number = yield starting_plus_one
  transformed_number * 2
end

add_one_then_do_something_then_double(2) do |num|
  # num is 3, here; we've been passed the (2 + 1)'d
  # number as an argument.
  num + 5
end
# => ((1 + 1) + 5) * 2 => 14

yield_self (https://docs.ruby-lang.org/en/trunk/Object.html#method-i-yield_self) is just a convenient method that everything has, so you can build a big chain of things, eg.

"This is a big string"
  .split(" ")
  .yield_self { |words|
    WordAnalyser.nouns(words)
  }
# => ["This", "string"]

Without it, you need to do something like:

WordAnalyser.nouns(
  "This is a big string"
    .split(" ")
    .etcetc
)

(Fiber.yield is... something you're never going to need unless you're implementing, like, a webserver or something.)

</wall-of-text>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment