Closures
A function can create another function and return it, like any other value. The new function then remembers the local variables of the function that created it, even after that function has ended. Here's a function that makes counters:
local function makeCounter()
local count = 0
return function()
count = count + 1
return count
end
end
local countEggs = makeCounter()
print(countEggs())
print(countEggs())
print(countEggs())This prints:
1
2
3Step by step: makeCounter() creates a local variable count with the value 0, then creates an anonymous function, returns it and ends. The returned function is stored in countEggs. Normally, the local variables of a function disappear when it ends, but count doesn't: the returned function uses it, so Lua keeps it for as long as that function exists. Each call of countEggs() increases this count and returns it.
A function together with the variables it remembers is called a closure. Every call of makeCounter creates a new count, so each counter has its own:
local function makeCounter()
local count = 0
return function()
count = count + 1
return count
end
end
local eggs = makeCounter()
local milk = makeCounter()
eggs()
eggs()
milk()
print("Eggs: " .. eggs())
print("Milk: " .. milk())This prints:
Eggs: 3
Milk: 2eggs() on a line of its own calls the counter and throws away the number it returns; that's allowed. Why not simply use one variable outside the function? Then any part of the program could change it, and for two counters you'd need two variables and two functions. In a closure, count is hidden: only the counter itself can reach it.
The parameters of the outer function are its local variables too, so a closure remembers them as well:
local function makeSeller(price)
return function(count)
return count * price
end
end
local sellCarrots = makeSeller(5)
local sellPumpkins = makeSeller(20)
print(sellCarrots(10), sellPumpkins(3), sellCarrots(2))This prints:
50 60 10sellCarrots remembers the price 5, and sellPumpkins remembers 20. Each returned function has its own price, set once when it was made.
Instructions
Write a function makeCounter with a parameter step. It returns a new function that adds step to its own count each time it's called (the count starts at 0) and returns the new count. Below it, add this code:
local eggs = makeCounter(6)
local milk = makeCounter(10)
eggs()
eggs()
milk()
print("Eggs: " .. eggs())
print("Milk: " .. milk())Emma collects eggs by the half dozen and milk in 10-liter cans, so the program prints:
Eggs: 18
Milk: 20Write a function makeBudget with a parameter coins. It returns a function with a parameter price: when price is at most coins, the function subtracts it from coins, and either way, it returns how many coins are left. Emma and Grandpa Joe each get their own budget. Add this code at the end:
local emma = makeBudget(20)
local joe = makeBudget(15)
print(emma(8))
print(joe(4))
print(emma(5))
print(emma(10))The last purchase costs more than Emma has left, so it doesn't happen. The program prints:
12
11
7
7Start programming for free
9/11