Learning Lua Step-By-Step (Part 8)

This entry is part 9 of 24 in the series Learning Lua Step-By-Step

Post Stastics

  • This post has 838 words.
  • Estimated read time is 3.99 minute(s).

Creating Lua Modules

In this eighth installment of the “Learning Lua Step-By-Step” series, we’ll explore how to create our own modules in Lua. Modules allow us to organize code into reusable units, making our programs more modular, maintainable, and easier to understand. We’ll cover the basics of creating modules, including defining module functions and variables, as well as loading and using modules in Lua programs.

Understanding Lua Modules

A Lua module is a collection of related functions, variables, and other definitions that can be loaded and used in other Lua scripts. Modules help in organizing code into logical units, promoting code reuse and separation of concerns.

Benefits of Using Modules

  • Modularity: Modules encapsulate functionality into reusable units, making it easier to manage and maintain code.
  • Code Reuse: Modules can be reused across multiple projects, reducing duplication and promoting consistency.
  • Encapsulation: Modules hide implementation details, exposing only the necessary interface to interact with the functionality they provide.
  • Namespace Management: Modules help in managing namespaces, preventing naming conflicts between different parts of the program.

Creating Lua Modules

Basic Module Structure

A Lua module is typically defined in a separate file with a .lua extension. The module file should return a table containing the functions, variables, and other definitions that it exports.

-- mymodule.lua

local M = {}

function M.sayHello()
    print("Hello from my module!")

return M

In the above example, we define a module named mymodule that exports a single function sayHello.

Loading and Using Modules

To use a module in a Lua script, we need to load it using the require function, which returns the table representing the module. We can then use the functions and variables exported by the module.

-- main.lua

local mymodule = require("mymodule")

mymodule.sayHello() -- Output: Hello from my module!

Advanced Module Techniques

Using Metatables for OOP

Modules can leverage Lua’s metatables to provide object-oriented programming (OOP) features such as encapsulation, inheritance, and polymorphism. Let’s see an example of using metatables to create a simple class in a module:

-- person.lua

local Person = {}

function Person:new(name, age)
    local obj = {
        name = name,
        age = age,
    setmetatable(obj, self)
    self.__index = self
    return obj

function Person:sayHello()
    print("Hello, my name is " .. self.name)

return Person
-- main.lua

local Person = require("person")

local person1 = Person:new("John", 30)
person1:sayHello() -- Output: Hello, my name is John

Using Closures for Encapsulation

Closures are a powerful feature in Lua that allow functions to capture and retain the environment in which they were created. This makes closures particularly useful for encapsulating state within modules, as they enable the creation of private variables and methods that are hidden from external code.

What is a Closure?

A closure is essentially a function that “closes over” its surrounding environment, meaning it retains access to the variables and parameters of its containing function even after the containing function has finished executing. This allows the closure to maintain state across multiple function calls, making it ideal for implementing encapsulation.

By defining variables within the scope of a closure, those variables become “encapsulated” or hidden from external access. This prevents external code from directly modifying or accessing the internal state of the module, ensuring data integrity and promoting a clear separation of concerns.

Example Usage

In the Counter module example above, the Counter function serves as a closure that encapsulates the count variable within its scope. The increment and decrement functions defined within the closure have access to the count variable, allowing them to modify its value while keeping it hidden from external code.

-- counter.lua

local function Counter()
    local count = 0

    return {
        increment = function()
            count = count + 1
            return count
        decrement = function()
            count = count - 1
            return count

return Counter
-- main.lua

local Counter = require("counter")

local counter = Counter()
print(counter.increment()) -- Output: 1
print(counter.increment()) -- Output: 2
print(counter.decrement()) -- Output: 1

In this way, closures provide a mechanism for implementing data encapsulation and access control in Lua modules, helping to create clean and maintainable code.


  1. Creating Modules:
  • Write a Lua module that defines a function to calculate the factorial of a number.
  • Use the module in a separate Lua script to calculate the factorial of a given number.
  1. Advanced Modules:
  • Extend the factorial module to include a function for calculating permutations and combinations.
  • Write a Lua script to demonstrate the usage of these additional functions.


In this tutorial, we’ve learned how to create Lua modules to organize and encapsulate code into reusable units. We explored basic module structure, loading and using modules, and advanced techniques such as using metatables for OOP and closures for encapsulation. By creating modules, we can write more modular and maintainable Lua code, promoting code reuse and separation of concerns.

In the next installment of our “Learning Lua Step-By-Step” series, we’ll delve into metaprogramming in Lua, exploring techniques for writing code that manipulates code. Stay tuned for more advanced Lua programming concepts!


Series Navigation<< Learning Lua Step-By-Step (Part 7)Learning Lua Step-By-Step (Part 9): Exploring Metatables and Operator Overloading >>

Leave a Reply

Your email address will not be published. Required fields are marked *