Menu
Coddy logo textTech

Singleton Table

Part of the Object Oriented Programming section of Coddy's Lua journey — lesson 63 of 70.

Sometimes you need exactly one instance of something in your entire program—a configuration manager, a logging system, or game settings. Creating multiple copies would cause problems: which one has the correct data? The Singleton pattern ensures only one instance exists.

In Lua, implementing a Singleton is surprisingly simple thanks to how modules work. When you require a module, Lua caches the result. Subsequent calls to require return the cached table, not a new one.

-- GameConfig.lua
local GameConfig = {
    volume = 80,
    difficulty = "normal"
}

function GameConfig:setVolume(v)
    self.volume = v
end

return GameConfig

Now, anywhere in your program:

local config1 = require("GameConfig")
local config2 = require("GameConfig")

config1:setVolume(50)
print(config2.volume)  -- 50 (same table!)

Both config1 and config2 reference the exact same table. Changes made through one variable are visible through the other. This happens automatically because Lua's require stores the returned value in package.loaded and reuses it.

Unlike the Factory pattern which creates new objects, a Singleton guarantees shared state across your entire application. This is ideal for global settings that multiple parts of your code need to access and modify consistently.

challenge icon

Challenge

Easy

Let's build a game settings manager using the Singleton pattern! You'll create a configuration module that ensures every part of your program accesses the exact same settings—no matter how many times it's required.

You'll organize your code across two files:

  • GameSettings.lua: Create a Singleton module that stores game configuration. Your settings table should include musicVolume (starting at 70), sfxVolume (starting at 100), and difficulty (starting at "normal"). Add three methods: :setMusicVolume(value), :setSfxVolume(value), and :setDifficulty(level) to modify these settings. Remember to return the table at the end of the module!
  • main.lua: Demonstrate that the Singleton works by requiring your GameSettings module twice into different variables. Use the first variable to change the music volume and difficulty. Then use the second variable to print all three settings—if the Singleton is working correctly, both variables reference the same table, so changes made through one are visible through the other.

You will receive two inputs:

  1. New music volume (a number)
  2. New difficulty level (a string like "easy" or "hard")

After modifying the settings through the first variable, print the three settings using the second variable, each on its own line in this order: music volume, sfx volume, then difficulty.

For example, if the inputs are 50 and hard, the output should be:

50
100
hard

If the inputs are 25 and easy, the output should be:

25
100
easy

Notice that the sfx volume remains at its default value of 100 since we never changed it—but the music volume and difficulty reflect the changes made through the first variable, proving both variables point to the same Singleton instance!

Cheat sheet

The Singleton pattern ensures only one instance of an object exists throughout your entire program. This is useful for configuration managers, logging systems, or game settings where multiple instances would cause data inconsistency.

In Lua, the Singleton pattern is implemented naturally through the module system. When you require a module, Lua caches the result in package.loaded. Subsequent calls to require return the same cached table, not a new one.

Creating a Singleton module:

-- GameConfig.lua
local GameConfig = {
    volume = 80,
    difficulty = "normal"
}

function GameConfig:setVolume(v)
    self.volume = v
end

return GameConfig

Using the Singleton:

local config1 = require("GameConfig")
local config2 = require("GameConfig")

config1:setVolume(50)
print(config2.volume)  -- 50 (same table!)

Both config1 and config2 reference the exact same table. Changes made through one variable are immediately visible through the other, ensuring shared state across your entire application.

The Singleton pattern differs from the Factory pattern: while Factory creates new objects, Singleton guarantees a single shared instance with consistent state.

Try it yourself

-- main.lua - Demonstrate the Singleton pattern

-- Read inputs
local newMusicVolume = tonumber(io.read())
local newDifficulty = io.read()

-- TODO: Require GameSettings module into a variable (e.g., settings1)

-- TODO: Require GameSettings module AGAIN into a DIFFERENT variable (e.g., settings2)
-- (If Singleton works correctly, both variables reference the same table!)

-- TODO: Use the FIRST variable to:
--   - Set the music volume to newMusicVolume
--   - Set the difficulty to newDifficulty

-- TODO: Use the SECOND variable to print the settings
-- Print each on its own line: musicVolume, sfxVolume, difficulty
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming