Passing Values
A coroutine and the program that resumes it can pass values to each other. Both ways go through the same two places: yield and resume.
Out of the coroutine. What you put in the parentheses of coroutine.yield(…) comes out of coroutine.resume. Emma's hens lay a different number of eggs each day:
-- Eggs for three days
local function henHouse()
coroutine.yield(4)
coroutine.yield(6)
coroutine.yield(5)
end
local hens = coroutine.create(henHouse)
print(coroutine.resume(hens))
print(coroutine.resume(hens))
local ok, eggs = coroutine.resume(hens)
print("Day 3: " .. eggs .. " eggs")This prints:
true 4
true 6
Day 3: 5 eggsresume returns true first, which means that the coroutine ran without an error, and then the values from yield. It's the same as with pcall from the lesson on functions (you'll meet the false at the end of this lesson). To work with the eggs, catch both values: local ok, eggs = coroutine.resume(hens).
Into the coroutine. Values go in through resume, after the coroutine. The first resume passes them to the function's parameters, as an ordinary call would. Every later resume passes them to the coroutine waiting at a yield: they become the result of that coroutine.yield():
-- An order at the market
local function order(customer)
print(customer .. " wants pumpkins.")
local count = coroutine.yield()
print(customer .. " buys " .. count .. " pumpkins.")
end
local sale = coroutine.create(order)
coroutine.resume(sale, "Grandpa Joe")
print("Emma counts her pumpkins.")
coroutine.resume(sale, 3)This prints:
Grandpa Joe wants pumpkins.
Emma counts her pumpkins.
Grandpa Joe buys 3 pumpkins.At the first resume, "Grandpa Joe" went into the parameter customer. The 3 came out of coroutine.yield() into the variable count. In between, the program did something else.
Both ways at once. A coroutine often keeps a value and updates it at every resume. Emma picks strawberries, and her basket keeps the total:
-- Strawberries in a basket
local function basket()
local total = 0
while true do
local picked = coroutine.yield(total)
total = total + picked
end
end
local strawberries = coroutine.create(basket)
coroutine.resume(strawberries)
local ok, total = coroutine.resume(strawberries, 12)
print("In the basket: " .. total)
ok, total = coroutine.resume(strawberries, 8)
print("In the basket: " .. total)This prints:
In the basket: 12
In the basket: 20Step by step: the first resume starts the function, total is 0, and the coroutine stops at yield(total). The second resume passes 12: yield returns it into picked, the total becomes 12, and the loop goes around to yield(total), which hands the 12 out as the result of resume. The third resume does the same with 8.
Notice two things. The loop while true do isn't endless here: it stops at every yield and goes on only when someone resumes the coroutine. When the program ends, the coroutine just stays paused, and that's fine. And the first resume only takes the coroutine to its first yield. If it passed 12, the 12 would go to the parameters of basket, which has none, and it would be lost.
Instructions
At the pumpkin contest, Emma's scale remembers the heaviest pumpkin. In scale, below the print, add a loop that runs forever. In it, the coroutine waits for the next pumpkin's weight with local weight = coroutine.yield(heaviest), and when weight is more than heaviest, it remembers it. At the end of the program, weigh a 12 kg pumpkin: resume contest with 12, catch the results in local ok, heaviest, and print the heaviest pumpkin like this:
The scale is ready.
Heaviest: 12 kgWeigh two more pumpkins, of 9 kg and 15 kg, and print the heaviest one after each of them. The program prints:
The scale is ready.
Heaviest: 12 kg
Heaviest: 12 kg
Heaviest: 15 kgStart programming for free
2/6