Lua Stateless Iterators
A stateless iterator is a plain function that keeps no position of its own and receives its position from the for loop on each call. The for loop supplies a state value and a control value, and the iterator returns the next control value and the next item.
The iterator takes state and control and returns the next pair
The state is the fruit table. The control value is the last index used.
local function next_item(t, i)
i = i + 1
if i <= #t then
return i, t[i]
end
return nil
end
local fruits = {"apple", "banana", "cherry"}
print(next_item(fruits, 0))
print(next_item(fruits, 1))
print(next_item(fruits, 3))The for loop supplies state and control
The for loop starts with control value 0. Each step feeds the returned index back as the next control value.
local function next_item(t, i)
i = i + 1
if i <= #t then
return i, t[i]
end
return nil
end
local fruits = {"apple", "banana", "cherry"}
for i, fruit in next_item, fruits, 0 do
print(fruit)
endControl values keep two walks separate
The function stores no position. Different control values start the walk at different places.
local function next_item(t, i)
i = i + 1
if i <= #t then
return i, t[i]
end
return nil
end
local fruits = {"apple", "banana", "cherry"}
print(next_item(fruits, 0))
print(next_item(fruits, 2))
print(next_item(fruits, 1))Example
local function next_step(state, current)
local value = current + state.step
if value <= state.limit then
return value
end
return nil
end
local state = {limit = 12, step = 3}
for v in next_step, state, 0 do
print(v)
end
print(next_step(state, 0))Key points
- State value: a value the for loop passes to the iterator unchanged on every call.
- Control value: the value that tells the iterator where the last call stopped.
- Iterator function: a plain function that takes a state value and a control value and returns the next control value and the next item.
- For loop protocol: the for loop calls the function with the state value and the control value and stops when the first returned value is nil.
- No stored position: two uses of the same iterator function can run at the same time without sharing a position.
In this example, the iterator adds the step from the state table to the current control value. The for loop starts at 0 and prints 3, 6, 9, and 12. The final manual call starts again from 0 and returns 3, which shows the function kept no position of its own.
Note
ipairs is a built-in stateless iterator whose state is the table and whose control value is the index.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
In the loop for v in next_step, state, 0 do, what does the for loop pass to next_step on its second call?