I am new to Ruby, is there a way to yield
values from Ruby functions? If yes, how? If not, what are my options to write lazy code?

- 75,521
- 93
- 229
- 319
5 Answers
Ruby's yield
keyword is something very different from the Python keyword with the same name, so don't be confused by it. Ruby's yield
keyword is syntactic sugar for calling a block associated with a method.
The closest equivalent is Ruby's Enumerator class. For example, the equivalent of the Python:
def eternal_sequence():
i = 0
while True:
yield i
i += 1
is this:
def eternal_sequence
Enumerator.new do |enum|
i = 0
while true
enum.yield i # <- Notice that this is the yield method of the enumerator, not the yield keyword
i +=1
end
end
end
You can also create Enumerators for existing enumeration methods with enum_for
. For example, ('a'..'z').enum_for(:each_with_index)
gives you an enumerator of the lowercase letters along with their place in the alphabet. You get this for free with the standard Enumerable methods like each_with_index
in 1.9, so you can just write ('a'..'z').each_with_index
to get the enumerator.

- 498
- 4
- 12

- 234,037
- 30
- 302
- 389
-
4`0.step` is an eternal enumerator since 1.9 – steenslag Mar 08 '15 at 22:18
I've seen Fibers used in that way, look at an example from this article:
fib = Fiber.new do
x, y = 0, 1
loop do
Fiber.yield y
x,y = y,x+y
end
end
20.times { puts fib.resume }

- 66,324
- 14
- 138
- 158
-
8In fact, in Ruby 1.9's `Enumerator` is implemented using `Fiber`. That was one of the main reasons for adding them, actually, because in Ruby 1.8 `Enumerator`s use continuations, but that is a) rather unwieldy and b) at that time continuations were going to be removed from the Ruby language. – Jörg W Mittag Mar 24 '10 at 09:38
If you are looking to lazily generate values, @Chuck's answer is the correct one.
If you are looking to lazily iterate over a collection, Ruby 2.0 introduced the new .lazy
enumerator.
range = 1..Float::INFINITY
puts range.map { |x| x+1 }.first(10) # infinite loop
puts range.lazy.map { |x| x+1 }.first(10) # [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

- 57,827
- 19
- 139
- 159
Ruby supports generators out of the box using Enumerable::Generator
:
require 'generator'
# Generator from an Enumerable object
g = Generator.new(['A', 'B', 'C', 'Z'])
while g.next?
puts g.next
end
# Generator from a block
g = Generator.new { |g|
for i in 'A'..'C'
g.yield i
end
g.yield 'Z'
}
# The same result as above
while g.next?
puts g.next
end
https://ruby-doc.org/stdlib-1.8.7/libdoc/generator/rdoc/Generator.html

- 164
- 1
- 6
Class Enumerator
and its method next
behave similar
https://docs.ruby-lang.org/en/3.1/Enumerator.html#method-i-next
range = 1..Float::INFINITY
enumerator = range.each
puts enumerator.class # => Enumerator
puts enumerator.next # => 1
puts enumerator.next # => 2
puts enumerator.next # => 3

- 138
- 7