# Coroutines Examples

Hi,

by popular demand (ok, 1 person asked for it ), I have put together a few simple examples on how to work with luas coroutines. The first one is this:

``````local cr

local function f()
local n
for n = 1, HEIGHT do
coroutine.yield(n)
end
end

function setup()
cr = coroutine.create(f)
end

function draw()
local ok, y = coroutine.resume(cr)
if ok then
background(40, 40, 50)
fill(255, 255, 255, 255)
ellipse(WIDTH / 2, y, 30)
text(y, 100, HEIGHT - 20)
else
close()
end
end
``````

This is a very basic setup of a main function and a coroutine, which illustrates a few things about coroutines. First, in order to use a coroutine, you first have to initialize it with coroutine.create. This does not yet start the coroutine, just creates a handle and some context for it. The coroutine is started and continued using coroutine.resume. The second thing this illustrates is that coroutine.yield works as a kind of return from the function, to which you can later come back again using coroutine.resume. Arguments to coroutine.yield are returned as the 2nd, 3rd and so on results from coroutine.resume. The first value returned is a status which tells you if you can call the coroutine again, if it is true, or not, i it is false. The third thing this example illustrates is that if you come back to a coroutine with resume, the function is in exactly the state you left it in.

A common use for this simple setup is creating iterators for for ā¦ in ā¦ do ā¦ end statements. This is so comon, tha a special function was introduced to ease that kind of stuff, namely coroutie.wrap. Example follows:

``````
local function enum(a, b)
return coroutine.wrap(
function()
local n
for n = a, b do
coroutine.yield(n)
end
end
)
end

function setup()
end

function draw()
local i
background(40, 40, 50)
fill(255, 255, 255, 255)
font("AmericanTypewriter")
fontSize(32)

for i in enum(12, 17) do
text(i, WIDTH / 2, HEIGHT - 32 * i)
end
end
``````

Coroutine.wrap calls coroutine.create on its argument and then returns a function that, when called, resumes the coroutine and returns all but the first (status) value returned by coroutine.resume.

For details about these functions, have a look at http://www.lua.org/manual/5.1/manual.html#5.2

More examples follow in the next 2 posts.

Part 2:

This is a more complex example of what yo can do with coroutines:

``````
local cr

local function f(tx, ty)
local x, y = math.random(WIDTH), math.random(HEIGHT)

while true do
local dx = tx - x
local dy = ty - y

if math.abs(dx) > math.abs(dy) then
dy = dy / math.abs(dx)
dx = dx / math.abs(dx)
else
dx = dx / math.abs(dy)
dy = dy / math.abs(dy)
end
x = x + dx
y = y + dy

tx, ty = coroutine.yield(x, y)
end
end

function setup()
cr = coroutine.create(f)
end

local tx, ty = math.floor(WIDTH / 2), math.floor(HEIGHT / 2)

function draw()
background(40, 40, 50)
strokeWidth(5)
stroke(255, 255, 255, 255)

local ok, x, y = coroutine.resume(cr, tx, ty)
if ok then
fill(0, 255, 14, 255)
rectMode(CENTER)
rect(tx, ty, 15, 15)
fill(255, 0, 0, 255)
ellipse(x, y, 30)
end
end

function touched(t)
tx = t.x
ty = t.y
end
``````

This mainly illustrates the communication between the main function and the coroutines, which works like this: as mentioned before, arguments passed to coroutine.yield are returned from coroutine resume, but this also works th other way round. On the first call to coroutine.resume on a freshly created coroutine the arguments to coroutine.resume are passed as arguments to the coroutine function, and for all subsequent calls, the arguments to coroutine.resume are returned from coroutine.yield. Here I use it to notify the little circle that is handled by the coroutine about the position of the last touch, and the circle handling coroutine returns the position of the circle to the main program, which then draws it.

3rd example follows.

This is a yet somewhat more complex example, having a bunch of coroutines and a very simple scheduler for them:

``````
local WorldWidth, WorldHeight = 16, 16
local MaxGrass = 3
local MaxSheep = 10
local MaxFed = 5

local cw = math.floor(WIDTH / WorldWidth)
local ch = math.floor(HEIGHT / WorldHeight)
local world = {}

local function initWorld()
local x, y
for x = 1, WorldWidth do
world[x] = {}
for y = 1, WorldHeight do
world[x][y] = math.random(MaxGrass + 1) - 1
end
end
end

local function drawWorld()
local x, y
background(131, 90, 29, 255)
pushStyle()
strokeWidth(0)
rectMode(CORNER)
for x = 1, WorldWidth do
for y = 1, WorldHeight do
if math.floor(world[x][y]) > 0 then
fill(0, 50 * world[x][y] + 100, 0, 255)
rect((x - 1) * cw, (y - 1) * ch, cw, ch)
end
end
end
popStyle()
end

local function updateWorld()
local x, y
for x = 1, WorldWidth do
for y = 1, WorldHeight do
world[x][y] = world[x][y] + 0.05
if world[x][y] > MaxGrass then world[x][y] = MaxGrass end
end
end
end

local function drawSheep(x, y)
strokeWidth(3)
stroke(0, 0, 0, 255)
fill(255, 255, 255, 255)
ellipse((x - 0.5) * cw, (y - 0.5) * ch, ch)
end

local function makeSheep(x, y)
local fed = MaxFed
local asheep = function()
while fed > 0 do
if math.floor(world[x][y]) > 0 then
fed = fed + 1
if fed > MaxFed then fed = MaxFed end
world[x][y] = world[x][y] - 1
else
fed = fed - 1
local n = math.random(4)
if n == 1 then
x = x + 1
elseif n == 2 then
y = y + 1
elseif n == 3 then
x = x - 1
else
y = y - 1
end
if x < 1 then x = 1 elseif x > WorldWidth then x = WorldWidth end
if y < 1 then y = 1 elseif y > WorldWidth then y = WorldWidth end
end
drawSheep(x, y)
coroutine.yield()
end
end

return coroutine.create(asheep)
end

local sheep = {}

function setup()
local n
initWorld()
for n = 1, MaxSheep do
sheep[n] = makeSheep(math.random(WorldWidth), math.random(WorldHeight))
end
end

local nsheep = MaxSheep
function draw()
local n
drawWorld()

if nsheep > 0 then
for n = 1, nsheep do
local ok, err =  coroutine.resume(sheep[n])
if not ok then
-- print(err)
end
end

for n = 1, #dead do
print("sheep died")
nsheep = nsheep - 1
end

updateWorld()
else
fontSize(82)
fill(0, 0, 0, 255)
text("all sheep died", WIDTH / 2, HEIGHT / 2)
end
end
``````

Here the āsheepā are coroutines that keep their state within themselves instead of in an object. We also let the coroutine die if a sheep dies so that the main function knows about it. As noted before, coroutine.resume returns false as the first return calue, if the coroutine can not be resumed. This can basically mean one of 2 things: it has terminated, or it has thrown an error. In order to distinguish between these 2, you can check the 2nd return value, which will be the error message.

I hope this gives some insight about how to use coroutines. There are more advances uses like control reversal or helper threads, but these are beyond the scope of these simple examples. This should however get you started. If there are questions left, just ask away.

Thatās brilliant, @gunnar_z. I havenāt actually used Luaās coroutines that much so this was a really interesting read. It also reminds me that I may have forgotten to include them in the autocomplete system.

I have heard about coroutines, but frankly speaking I have no idea why to use those nor that I have understood the concept. Does this allow parallel processing of tasks, does it increase speed? So in a nutshell: why would I like to use coroutines and for what are they good for? Sorry for this stupid question, but I simply canāt get the point.

@CrazyEd coroutines are like cooperatively scheduled threads. They donāt increase speed because unlike preemptively scheduled threads they can not use multiple processors. They are a means to structure your program in such a way that you have independent parts loosely cooperating. Study the above examples, they can give you an idea about what coroutines can do for you.

Thanks so much! Wonderful!

Excellent explanation, @gunnar_z! @Simeon was impressed enough that when I was asking him elsewhere about coroutines, he pointed me here.

One of the reasons Iām looking into them is that theyāve been offered up as a ābetter way to do callbacksā, and Iām trying to figure out just how that might happen. I still donāt understand it, yet - But I have never let that stop me before, and I wonāt let it do so now!

(one of the features in the upcoming beta that I hope passes muster with apple uses callbacks, and itās less pretty than I had hoped it might be - Iām trying to figure out how to wrap it up with coroutines so it looks more ānormalā in usage, if that makes any sense).

@Bortels when I rework this for the wiki, I plan to also cover how to use coroutines for control reversal, maybe that will help with what youāre trying to do.

This is a really useful post thanks.

What Iāll be using it for is the āinitā phase of my app.

I intend to create as many of my resources as possible in code (I canāt draw for toffee) by drawing to offscreen images. This will allow me to just keep running the generation code in the background on the init screen and then allow a nice progress bar to be displayed (like the cargobot one) in the forergound which is simply scaled by a progress variable thatās updated as resources are generated.