A Quick Look at Generators

November 7, 2010 – 8:12 pm

Generators are objects that store the stack and state of a function call in response to a yield statement. They can then be called to restore the previous state of that function call. The function will resume execution just after the last yield statement. A generator will exit when a return statement is encountered. You can do that explicitly or just let the function exit normally.

A generator is created automatically when the function in question, from here on referred to as generator function, is called for the first time. A function is a generator function if and only if it contains a yield statement somewhere in its body.

function range(lo, hi)
  for x = lo to hi
    yield x
  end
end
 
c = range(0, 10)

The generator type overloads the operator toBoolean. It will evaluate to true if it is yielded and can be resumed. Otherwise it will evaluate to false. Trying to resume the generator in that state will raise an exception. It is always safer to test before calling if you are unsure.

print c() #=> 0
print c() #=> 1
print c() #=> 2
 
loop  
  x = c()
  break when !c # Exit loop if c returned.
  print x       # Otherwise print the value yielded.
end

You can also use a generator as the subject of a for loop. This makes it easier to iterator over all the values it will yield.

for x in range(0, 5)
  print x
end

They can also be used to iterate objects. Below attrs is an InstanceMethod generator that can be used to loop through all the values in an Employee object.

class Employee
  function init(name, age, position)
    self.name = name
    self.age = age
    self.position = position
  end
 
  function attrs()
    yield self.name
    yield self.age
    yield self.position
  end
end
 
employee = Employee.new "Bob", 32, "Software Engineer"
for a in attrs of employee
  print a
end

Like the return statement, the yield statement can handle multiple values.

function even_odd_pairs(x)
    for n = 0 to x*2 by 2
      yield n, n+1
    end
end
 
iter = even_odd_pairs(5)
 
a,b = iter()
print a,b #=> 0 1
 
a,b = iter()
print a,b #=> 2 3

This can be extended to the for-in loop’s they are used in. If the generator does not produce enough values the unpack rules for assignment will be applied. You can refer to the documentation to learn more about unpacking.

for x, y in even_odd_pairs(3)
  print x, y
end

Those are the basics to using Generators in Pika. The best way to learn more is to try it out for yourself. If you have any questions or comments, please, don’t hesitate to ask.