Subtle issue with Lua require

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
hardcrawler
Prole
Posts: 12
Joined: Fri Jun 27, 2014 11:31 pm

Subtle issue with Lua require

Post by hardcrawler »

Just a random Lua tip. This is something I didn't know, and it cost me a few hours.

Code: Select all

local foo = require("libs.foo")
local foo2 = require("libs.foo")
if foo2 ~= foo then
        print("This will not happen")
end

local foo3 = require("libs/foo")

if foo3 ~= foo then
        print("Oh my.  Using a slash instead of a dot is broken.")
end
When you use require, Lua keeps track of the things you have required previously. If you require the same library multiple times, it is only executed once.

Lua keeps track of this in a table somewhere. In other news, Lua supports multiple syntaxes for require. One of these syntaxes allows a "/" to denote directories. One of the other syntactic behaviors allows a "." to denote directories.

Long story short, if you mix and match the "." syntax with the "/" syntax, require will execute the required script multiple times.

This cost me 3 hours. Remember kids: Stay consistent with your require syntax!
User avatar
Jasoco
Inner party member
Posts: 3726
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Subtle issue with Lua require

Post by Jasoco »

Is there any reason you can't just use love.filesystem.load(file)() to execute a file instead when you need to load it multiple times?
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: Subtle issue with Lua require

Post by bartbes »

hardcrawler wrote:In other news, Lua supports multiple syntaxes for require.
It doesn't. It just doesn't prevent you from using the wrong one (which is the slash).
hardcrawler wrote: Long story short, if you mix and match the "." syntax with the "/" syntax, require will execute the required script multiple times.
Of course, all this works with module names, if you give it another module name (an incorrect one at that), it considers it a different module.
User avatar
hardcrawler
Prole
Posts: 12
Joined: Fri Jun 27, 2014 11:31 pm

Re: Subtle issue with Lua require

Post by hardcrawler »

bartbes wrote: Of course, all this works with module names, if you give it another module name (an incorrect one at that), it considers it a different module.
Bear in mind that the Lua loads the module in both cases. It doesn't generate an error. I use the "." syntax everywhere, I just happened to mess it up in one case, and it didn't generate an error, but loaded two copies of the module.

I consider this to be a pretty subtle and interesting behavior, worthy of note.
User avatar
hardcrawler
Prole
Posts: 12
Joined: Fri Jun 27, 2014 11:31 pm

Re: Subtle issue with Lua require

Post by hardcrawler »

Jasoco wrote:Is there any reason you can't just use love.filesystem.load(file)() to execute a file instead when you need to load it multiple times?
One of the features of require is that it will only perform file I/O and parsing on a particular module once. Subsequent uses of "require" will simply return the table resulting from the last call to require for that module. (It was the violation of this behavior that sparked my initial post).

love.filesystem.load does not have this advantage. It will re-parse and interpret the file on every call.

Code: Select all

        local chunk = love.filesystem.load( "libs/foo.lua" )
        local chunk2 = love.filesystem.load( "libs/foo.lua" )
        assert(chunk == chunk2, "Nope, they aren't the same.")
paulclinger
Party member
Posts: 227
Joined: Thu Jun 28, 2012 8:46 pm

Re: Subtle issue with Lua require

Post by paulclinger »

hardcrawler wrote:Bear in mind that the Lua loads the module in both cases. It doesn't generate an error. I use the "." syntax everywhere, I just happened to mess it up in one case, and it didn't generate an error, but loaded two copies of the module.
Right, there is no error. You just used a different way to load a module. There is no mystery in how it' handled: after a module is loaded successfully, its result is saved in `package.loaded[name]` and for each `require`, Lua checks if the value is already present in `package.loaded` table and returns that value. So, in your case, one call to require created `package.loaded['libs.foo']` and the other call created `package.loaded['libs/foo']`; both were executed successfully and stored as two different results. This also means that you can control "require" behavior by setting `package.loaded[module]` to nil to force require to reload the package again.
Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests