Lua - Singleton Module
A singleton module refers to a module which once loaded provides a single instance and can be used for consistent data across the modules where it loaded. A singleton module is generally used to provide a consistent data which is to be used by multiple modules. We can define a set of functions as well in the singleton module which modify the data.
Lua, by default provide module caching. Which means once a module is loaded, it is cached and in further occurences of module loading, the cached copy will be used. This caching is very much effective and useful when we need to have singleton modules.
Creating a Singleton Module
Standard approach to create a singleton module is by returning a table as module. We can store module state as table variables and module behavior using functions on table. Due to module caching, our application will receive same table whenever require is called on the module.
Example - Singleton Module
Let's create a file settings.lua in current directory to act as application's global settings wizard.
settings.lua
local settings = {
-- variables to store state of module
theme = "DARK",
volume = 0.80
}
-- function to update theme
function settings.setTheme(theme)
settings.theme = theme
print("Theme is updated to:", theme)
end
-- function to update volume
function settings.setVolume(volume)
if volume >= 0 and volume <= 1 then
settings.volume = volume
print("Volume is updated to:", volume)
else
print("Invalid volume. It must be between 0 and 1.")
end
end
function settings.get_settings()
return settings
end
return settings
Create modules to use the settings module.
module_wooden_speaker.lua
local settings = require("settings")
-- print the current theme
print("Module Wooden Speaker - Current theme:", settings.theme)
-- update theme
settings.setTheme("LIGHT")
-- print the updated module
print("Module Wooden Speaker - Updated theme:", settings.theme)
module_plastic_speaker.lua
local settings = require("settings")
-- print the current theme
print("Module Plastic Speaker - Current theme:", settings.theme)
-- update volume
settings.setVolume(0.5)
Let's now import both above modules in main code and see the impact of singleton module settings.
main.lua
-- load both modules
require("module_wooden_speaker")
require("module_plastic_speaker")
-- load settings module
local settings = require("settings")
-- print the final values of settings
print("Main - Settings:", settings.theme, settings.volume)
Output
When we run the above program, we will get the following output−
Module Wooden Speaker - Current theme: DARK Theme is updated to: LIGHT Module Wooden Speaker - Updated theme: LIGHT Module Plastic Speaker - Current theme: LIGHT Volume is updated to: 0.5 Main - Settings: LIGHT 0.5
As evident from the output, the settings modules is loaded in three modules module_wooden_speaker, module_plastic_speaker and main but each module receives the same settings table. Changes done in one module are reflecting in other modules. This makes settings modules effectively a singleton module.
Characteristics of Singleton Module in Lua
Single Copy − A module is cached by default in Lua, so at a time only single copy is present in memory.
Globally Accessible − Using require, we can load the singleton module in any part of the application.
Shared − Changes made to singleton state in any part of the application will be visible to consequent part of application.
Encapsulation − Althouh singleton state is shared, we can still achieve encapsulation by providing a controlled access on internal logic using functions.
Use cases of Singleton Module
Managing Configuration − A singleton module can be used to store common configurations or settings.
Logging − A singleton module can act as a single tool to log events.
Managing Databased Connections − We can use singleton module to maintain a connection pool for database connections.
Managing Game State − A singleton module can be used to hold current state of the game to be used accross multiple arenas.