Errors in Coroutines

What happens when something goes wrong inside a coroutine? On the second day, Hugo's route runs into trouble:

-- Hugo loses his map
local hugo = coroutine.create(function()
    coroutine.yield("market")
    error("Hugo lost his map")
    coroutine.yield("farm")
end)

print(coroutine.resume(hugo))
print(coroutine.resume(hugo))
print(coroutine.status(hugo))
print(coroutine.resume(hugo))
print("The day goes on.")

This prints:

true	market
false	main.lua:4: Hugo lost his map
dead
false	cannot resume dead coroutine
The day goes on.

An error inside a coroutine doesn't stop the program, only the coroutine. The coroutine is dead from then on (it never gets to the farm), and resume returns false and the error message, just like pcall. Resuming a dead coroutine isn't an error either: you get false and cannot resume dead coroutine.

That's handy, because one broken character doesn't stop the whole game. But it's also a trap: if you don't look at what resume returns, the error disappears without a trace, and the coroutine just quietly stops doing anything. So when something in a coroutine doesn't happen, print what resume returns. In a finished program, check the first value: after local ok, message = coroutine.resume(hugo), ok is false when something went wrong, and message says what.

A generator is different. A function from coroutine.wrap doesn't return true or false, so it passes the error on, and the program stops, as with any other error:

-- Hugo loses his map again
local nextStop = coroutine.wrap(function()
    coroutine.yield("market")
    error("Hugo lost his map")
end)

print(nextStop())
print(nextStop())
print("This line never runs.")

This prints:

market
main.lua:8: main.lua:4: Hugo lost his map

The message has two line numbers: main.lua:8: is where the generator was called, and main.lua:4: is where the error happened inside it. A used-up generator stops the program the same way, with cannot resume dead coroutine. If you need to catch an error from a generator, call it with pcall, like any other function: local ok, stop = pcall(nextStop).

One more error you already know from this lesson: coroutine.yield() outside a coroutine, for example in a function you called directly, ends with attempt to yield from outside a coroutine.

Instructions

Hugo buys a pumpkin for 20 coins every day. Run the program: days 3 and 4 print nonsense, because on those days, coins holds an error message, not a number. (error(…, 0) leaves out the line number, as you know from the lesson on functions.) Check ok: when it's false, print the day and the message instead, like Day 3: Hugo has only 10 coins left. The program prints:

Day 1: Hugo has 30 coins
Day 2: Hugo has 10 coins
Day 3: Hugo has only 10 coins left
Day 4: cannot resume dead coroutine

Resuming a dead coroutine makes no sense. At the start of each day, check Hugo's status: when it's dead, print the day and Hugo has gone home. instead of resuming him. The program prints:

Day 1: Hugo has 30 coins
Day 2: Hugo has 10 coins
Day 3: Hugo has only 10 coins left
Day 4: Hugo has gone home.

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

5/6