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.

Advertisements