Writing Lua Modules

Introduction

With Lua 5.2 the recommended way to write modules changed. Instead of using module(“mymodule”, package.seeall) the recommendation now is to create a local table, put all of the module’s functions in it and return the table. The big difference is a local table does not register the module in the global namespace.

Personally, I like this change. It keeps the modules self contained and reduces name collisions. That said, I’ve found information on using this concept to be a bit lacking. Most of the information I’ve seen is either very basic or highly convoluted and trying to create a full OOP class system in Lua using Lua.

Basic Example

Typically, you’ll see examples like the following for writing Lua modules:

functions_module.lua

local M = {}

function M.func1()
    print("func1")
end

function M.func2()
    print("func2")
end

return M

main_functions.lua

local fm = require("functions_module")

fm.func1()
fm.func2()

Using this module:

$ lua main_functions.lua 
func1
func2

This module works fine if all you want to do is provide a collection of semi-independent functions. It’s not clear how you would emulate say a C++ class.

My take on writing modules

I’ve been using the following module blueprint. It doesn’t support inheritance but it does support storing state within each instance of the module. The fact that I mostly work in C, the lack of inheritance doesn’t really bother me.

If you think about an object in C what you really have is a data pointer and functions that take/use that data pointer. Something like:

int func1(func_data_t *d, int arg1)

The basic example above is more or less this idea. The issue with it is you have to track the data used by each function. This isn’t very Lua like. Instead it would be useful to let the object store it’s data.

example_module.lua

local M = {}
local M_mt = { __metatable = {}, __index = M }

function M:new(arg1)
    if self ~= M then
    	return nil, "First argument must be self"
    end

    local o = setmetatable({}, M_mt)
    o._arg1 = arg1
    return o
end
setmetatable(M, { __call = M.new })

function M:_private1(arg1)
    print("passed arg = " .. (arg1 or "nil"))
end

function M:public1()
    print("self._arg1 = " .. (self._arg1 or "nil"))
end

function M:public2(arg1)
    self:_private1(arg1)
    self:public1()
end

function M_mt:__tostring()
    return string.format("%s", o._arg1)
end

return M

Breaking this down we have M and a metatable for M. The metatable points to M for __index.

The idea behind new is we create a table (o) using setmetatable and using the M_mt as it’s metatable. We set internal data members of o and they’re prefixed with _. This is a convention (think Python) to denote that the data is considered private. New then returns the table. The returned value can be used to call any of the M functions which can be called using : to get a reference to that particular table and it’s internal data members.

You’ll notice we have function M:new(arg1) using : instead of . like you’ll typically see with Lua modules. This is on purpose because it allows us to register new to __call via setmetatable(M, { __call = M.new }). This allows use to do mod() in addition to of mod:new(). Notice that this setmetatable call is on M not M_mt. This allows us to do mod() but still allows us to set a __call function on M_mt (for the object returned by new).

At the very top of the file we set the __index of M_mt which directly when we create M_mt. This is a connivence since we’re having __index reference M. Other meta functions we can create directly in the module. See function M_mt:__tostring() for example.

Here is an example of various ways we can construct and use the module:

main_example.lua

local exm = require("example_module")

mym1 = exm:new("mym1")
print(mym1)
mym1:public1()
mym1:public2("a")

print()

mym2 = exm("mym2")
print(mym1)
mym2:public1()
mym2:public2("b")

print()

mym3 = exm.new(exm, "mym3")
print(mym1)
mym3:public1()
mym3:public2("c")

And the output when we run the example:

$ lua main_example.lua 
mym1
self._arg1 = mym1
passed arg = a
self._arg1 = mym1

mym2
self._arg1 = mym2
passed arg = b
self._arg1 = mym2

mym3
self._arg1 = mym3
passed arg = c
self._arg1 = mym3

Overall I’ve found the above approach to be very easy to use when constructing Lua modules. The only real drawback I’ve seen other than not supporting some form of inheritance is the fact that new must be called with a :. This is not what most people will be used to. We could change it to M.new instead but we’d loose the ability to register __call to new on M. That said, I’ve found this module implementation works well for me needs.