Everything you need to know about lua modules

Hi folks,
I’ve done tons of research and testing on the proper way to write a module in Lua. So I thought I’d share it with you.

Most people would simply write a module like a regular script starting with
[lua]module(…, package.seeall)[/lua]
Have a look here to get some ideas about why it is a bad practice.

What you should write, according to many gurus is this:
[lua]-- File: myModule.lua
– Author: me

– ***************************
– Private part of your module
– ***************************

local myOtherModule = require( “myOtherModule” )

local privateVar1 = “Foo”
local privateVar2 = 23

local privateFunction1()
– do something
end

local privateFunction2()
– do something else
end
– The module table
local myModule = {}

– **************************
– Public part of your module
– **************************

myModule.publicVar1 = 5

myModule.publicFunction1 = function()
myModule.publicVar1 = 22
– do something
end

myModule.publicFunction2 = function()
– do something else
end

return myModule[/lua]

A big advantage of this technique is that it avoids cluttering the global environment with unnecessary stuff. And even more important, it allows you to write private functions and variables that won’t be accessible outside the module.

To call and use the module, you would just write:
[lua]local myModule = require(“myModule”)
myModule.publicFunction1()[/lua]

Now, let’s talk a bit about memory. As you are aware, you should call require in every script that makes use of the module. Worry not, the require function actually loads the module only once.
What it does is that it stores the result in a special table called “package.loaded”. So if you load “myModule”, you will see an entry as package.loaded.myModule (or package.loaded[“myModule”]).
When the module gets loaded the first time, the return value is stored as the value associated with the key “myModule”.

For a simple script with no return value, it’s actually “true”. Why? Because if you don’t specify a return value, it is assumed to be “nil”. And setting the table entry to “nil” would mark it as ready to be deleted by the GC. And this can’t happen as “require” needs to know which module is loaded. So what’s in this entry when you create a module? A reference to your table of course. So this is what happens when you call require multiple times:

First time:

  1. The script is executed. An entry is created in “package.loaded” and the value is set to the return value of your script. In case of a module, it’s gonna be a table.

  2. the local variable is assigned the reference to the table

Second time:

  1. “require” checks in “package.loaded” and sees that it’s already available. nothing is done.

  2. the local variable is assigned the reference to the table
    As you can see, no time and memory is wasted in multiple calls to “require”. BUT. And this is a big BUT (no, not a big butt …):
    The memory used by the module is never freed!

What the heck? Yep, when the script requiring a module finishes its task, the local variable referencing the table is GCed. But there is still a reference to this table in “package.loaded” so the table never gets freed. Bugger.

You can check it out by yourself:
[lua]main.lua:
– load a module
local module = require(“module”)

– quit main and execute the script
require(“script”)
module.lua:
local myModule = {}
myModule.dummyVar = 1
return myModule
script.lua:
for k,v in pairs(package.loaded) do
print(k,v)
end[/lua]

So how do you get rid of the loaded module? Easy:
[lua]package.loaded[“myModule”] = nil
collectgarbage(“collect”)[/lua]

And with this, I’m going back to work. I apologize in advance for any typos / english error as I’m french.

Seth [import]uid: 51516 topic_id: 9114 reply_id: 309114[/import]

Thankyou :slight_smile:
Is there any performance loss using package.seeall?
And am I correct in believing

require(“modulename”)

is shorthand for

modulename = require(“modulename”)

in that they both load the module in global scope, and using local as you have is much better?
[import]uid: 34945 topic_id: 9114 reply_id: 33221[/import]

I can’t really tell about the performance but it should be very similar, if not completely equal.

As for your second question, require(“modulename”) is different from modulename = require(“modulename”). The first code just loads the module but you can’t access it. The second code loads the module and assign a reference to a global variable “modulename”. Which is something you should avoid if you can. If you don’t/won’t, be sure to set the global variable to nil when you’re done with it. [import]uid: 51516 topic_id: 9114 reply_id: 33223[/import]

Thanks for the pointers Seth, I’m going to modify my code according to your advice! I have a little design challenge that I hope you can help me with:

I call some modules (level1.lua, level2.lua, etc) from my main.lua to change scenes. However, every module needs to perform a particular task (construct the same building, for example). So I would like to put the function that constructs the building into its own module (building.lua). However, I cannot successfully get the ‘level’ modules to call the functions in the ‘building’ module.

Can modules call functions within other modules? (I think your example above shows the calls from main). If modules can call functions within other modules, can you show a simple example? It would be much appreciated. Thanks!
[import]uid: 31874 topic_id: 9114 reply_id: 33240[/import]

Can modules call functions within other modules? Hell yeah!

[lua]main.lua:
local level1 = require(“level1”)
local level2 = require(“level2”)

level1.lua:
local building = require(“building”)
local eiffelTower = building.constructEiffelTower()
– do stuff, like destroy the Eiffel tower

level2.lua:
local building = require(“building”)
local eiffelTower = building.constructEiffelTower()
– do stuff, like paint the Eiffel tower[/lua]

But I actually recommend using a “proxy” for loading levels, something in the line of this:
[lua]level.lua:
local function load(level)
– do stuff (cleanup, …)
local levelLayer = require(level)
gameScene:insert(levelLayer)
– do common stuff (add the game interface, …)
– do other stuff (set runtime events, …)
end

return { load = load }
level1.lua:
local levelLayer = display.newGroup()
– add stuff
return levelLayer[/lua]

And then to load a level:
[lua]local level = require(‘level’)
level.load(“level1”)[/lua] [import]uid: 51516 topic_id: 9114 reply_id: 33243[/import]

Thanks Seth! I was doing just that and it wasn’t working for me. I’m going to re-write a simple ‘main’ and a couple level ‘modules’ again and build back up from there. My modules are large and I’m sure I must have a bug I’m not seeing.

I like your proxy dersign - it’s straightforward! I was using the director class (director:changeScene(“level1”)). [import]uid: 31874 topic_id: 9114 reply_id: 33244[/import]

I’ve been using :
[lua]require(“object”)
newobject = object:new()
print(newobject.retVar1()) – “Foo”
print(newobject.retTotal()) – “15”[/lua]
where object.lua contains this
[lua]–object.lua
–class for object

module(…) --or module(…,package.seeall) if I need access to other modules
function new()
local newobj = {}
newobj.var1 = “Foo”
newobj.var2 = “Bar”
newobj.n = 7
newobj.m = 8

local function fSum(a,b)
return a+b
end

function retVar1()
return newobj.var1
end

function retTotal()
return fSum(newobj.n,newobj.m)
end

return newobj
end[/lua]

i.e. I access it using its filename which seems to be automatically created as a variable
I know its slightly different in that its an object class, but it works :slight_smile: [import]uid: 34945 topic_id: 9114 reply_id: 33285[/import]

Thanks for the detailed explanation! Would the change scene alternative described in this post be as efficient even though it uses module(…, package.seeall)? http://developer.anscamobile.com/forum/2011/02/14/easy-screen-transitions-director-alternative [import]uid: 40033 topic_id: 9114 reply_id: 35938[/import]

I havent bothered to download the file and try it, so I may be talking out of place here, but from the description, I can’t see how using package.seeall would be useful.
As far as I can see, it allows a module to see other modules, and if this one is taking a screenshot, and returning it, it doesn’t use any other modules, so is just a (albeit negligible in the scheme of things) waste of resource.
(on iphone, so can’t see the code anyways)
:slight_smile: [import]uid: 34945 topic_id: 9114 reply_id: 35996[/import]

I checked the texture memory in my simple game (animated sprites with physics, scrolling background). It looks like the code cleans it up nicely:

  1. shortly after launching game from splash screen:
    game curr texture memory used (bytes) = 4005888

  2. when the game is in play:
    curr texture memory used (bytes) = 2957440

  3. initial bytes when first changed back to splash screen:
    curr texture memory used (bytes) = 1114112 then

  4. sitting at splash screen
    curr texture memory used (bytes) = 65536

This is the code in the main.lua (pass sceneGroup back from other modules):

[lua]–main.lua
– from x-pressive.com

function ChangeScene(NextScene)

– MAKE A SCREENSHOT OF THE SCENE TO REMOVE,
– CENTER & SCALE SCREENSHOT TO CORRECT SIZE
local Screenshot = display.captureScreen( false )
Screenshot.yScale = (display.contentHeight/ Screenshot.height)
Screenshot.xScale = Screenshot.yScale
Screenshot.x = display.contentWidth*.5
Screenshot.y = display.contentHeight*.5

– REMOVE THE CURRENT SCENE (SCREENSHOT STAYS)
CurrScene:removeSelf()

– CREATE A NEW SCENE
CurrScene = NextScene.CreateScene()

– SCENE TRANSITION
display:getCurrentStage():insert(Screenshot)

– TRANSITION TO NEXT SCREEN
transition.to(Screenshot, {

time = 400,
xScale = .5,
yScale = .5,
rotation = 0,
transition = easing.inQuad,
onComplete = function()
Screenshot:removeSelf(); Screenshot = nil

end
}) [/lua]

end
[import]uid: 40033 topic_id: 9114 reply_id: 36041[/import]

Re: I can’t see how using package.seeall would be useful.

well, if your module calls display. or print(… in your module you’ll need to reference the class that contains display or print. I tried to change module(…, package.seeall) to module(…) and it errored out quickly siting the familiar "attempt to index global ‘display’ (a nil value). I suppose you could limit your references to the class that contains display, assuming you don’t reference other classes, but the documentation doesn’t show the base class names. [import]uid: 38348 topic_id: 9114 reply_id: 65869[/import]

Great post, thanks for the info and link to the discussion on lua-users.org.

I have a question for you. In my app, I am loading modules and watching the texture memory increase. However, when I am finished with the module and remove it, the textured memory never decreases back to the level that I had before loading the module. I added in your two lines:
package.loaded[“myModule”] = nil
collectgarbage(“collect”)
However, I still have increased memory. I even checked to see if package.loaded[“myModule”] is not nil, after calling the two lines above. It is nil but didn’t decrease the memory. Could it be that there is a local variable in the module that I didn’t remove and it is sticking around in memory even after the package.loaded[“myModule”] is nil?

Any incite here would be appreciated.

thanks [import]uid: 38348 topic_id: 9114 reply_id: 65871[/import]