Iterator Pattern
Part of the Object Oriented Programming section of Coddy's Lua journey. Lesson 64 of 70.
When you have a collection of items stored inside an object, you often want to loop through them. Lua's generic for loop works with any iterator function: it calls the function before every pass and stops when the function returns nil.
The Iterator pattern gives the object a method that returns such a function. The function keeps its position in a local variable, so the position belongs to one loop, not to the collection:
local Collection = {}
Collection.__index = Collection
function Collection:new()
local obj = { items = {} }
setmetatable(obj, Collection)
return obj
end
function Collection:add(item)
table.insert(self.items, item)
end
function Collection:iter()
local index = 0
return function()
index = index + 1
return self.items[index]
end
endEach call to bag:iter() creates a new function with its own index, starting at 0. The function is a closure: it can still use index and self after iter has returned. Past the last item, self.items[index] is nil, and the loop stops:
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag:iter() do
print(item) -- apple, then banana
end
for item in bag:iter() do
print(item) -- apple, then banana again
endKeep the position out of the collection itself. If the object stored self.index and acted as its own iterator, the first loop would leave the index at the end, so a second loop would print nothing, and a loop that stopped early with break would make the next loop start in the middle.
Challenge
EasyLet's build a Playlist class that you can loop through with Lua's generic for loop! You'll implement the Iterator pattern with a :iter() method that returns an iterator function.
You'll organize your code across two files:
Playlist.lua: Create a Playlist class that stores songs internally. Your class needs a:new()constructor that initializes an empty songs list and an:addSong(title)method that adds a song to it. Most importantly, add an:iter()method that returns a new function each time it is called. That function keeps its position in a local variable and returns the next song on each call, ornilwhen there are no more songs.main.lua: Require your Playlist module and create a new playlist. Add songs to it based on the inputs you receive, then use a genericforloop overplaylist:iter()to print each song title on its own line.
Because every call to :iter() starts at the first song, the same playlist can be looped over any number of times.
You will receive three inputs, each representing a song title to add to your playlist (in order).
For example, if the inputs are Bohemian Rhapsody, Stairway to Heaven, and Hotel California, the output should be:
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaIf the inputs are Yesterday, Imagine, and Let It Be, the output should be:
Yesterday
Imagine
Let It BeTry it yourself
-- Require the Playlist module
local Playlist = require('Playlist')
-- Read three song titles from input
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Create a new playlist using Playlist:new()
-- TODO: Add the three songs to the playlist using :addSong()
-- TODO: Use a generic for loop over playlist:iter()
-- and print each song title on its own line
-- Hint: for song in playlist:iter() do ... end
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1The 'Self' Concept
Tables with FunctionsExplicit 'self'The Colon SyntaxDot vs ColonRecap - Moving Point4Project: Digital Bank
Project SetupDeposit Method7Polymorphism & Overriding
Overriding MethodsCalling Parent MethodsDuck TypingCommon InterfaceChecking TypeRecap - Employee Roles10Project: Shape Manager
Project SetupRectangle ClassCircle ClassPerimeter MethodShape CollectionTotal AreaFilter Shapes2Class Prototype Pattern
The Prototype ConceptLinking with __indexThe :new() ConstructorInitializing AttributesIndependent InstancesRecap - Car Factory5Operator Overloading in OOP
Adding ObjectsSubtracting ObjectsConcatenating ObjectsComparing Objects (<, >)Recap - Wallet Math8Encapsulation
Naming ConventionsClosures for PrivacyAccess via ClosuresRead-Only TablesValidation LogicRecap - Secure Vault11Design Patterns (Lite)
Factory FunctionsSingleton TableIterator PatternObserver (Listener)Recap - Logger Factory3Object State and Behavior
Instance VariablesGetter MethodsSetter MethodsCalculated PropertiesFormatting StringsEquality ChecksRecap - Student Grade6Inheritance Basics
The Inheritance SetupInheriting MethodsExtending the ConstructorAdding Child MethodsShared vs UniqueRecap - Shape HierarchyPractice on your own: Online Lua compiler