One area of Lua which commonly trips people up is the loading of code. I shall attempt to cover the process of loading code, if only to have something to point people at when they ask in the future.

A typical example

A common misunderstand of how Lua loads code looks something like the following:

I have the following file called foo.lua:

function foo(x, y)
 print(x + y)
end

Then I load it like this:

foo = loadfile("foo.lua")
foo(2, 3)

I am expecting to see 5 as the output, but nothing happens.

The above example is about as bad as things can get, as if you call foo a second time, then it'll start doing what was expected, and if on the other hand you replace loadfile with dofile, then Lua will complain with "attempt to call global 'foo' (a nil value)".

A typical fix

As an immediate fix, the correct way to load foo.lua and run the function contained within it is as follows:

loaded_chunk = assert(loadfile("foo.lua"))
loaded_chunk()
foo(2, 3)

To understand what is going on, let us inspect what Lua's global table looks like after each line of execution. To start with, before any lines are executed, we just have the standard library in the global table:

(standard library; print, math, loadstring, string, etc.)

After executing loaded_chunk = assert(loadfile("foo.lua")), a new entry has been added to the global table:

(standard library; print, math, loadstring, string, etc.)

loaded_chunk = function(...)
  function foo(x, y)
    print(x + y)
  end
end

After executing loaded_chunk(), another new entry gets added to the global table:

(standard library; print, math, loadstring, string, etc.)

loaded_chunk = function(...)
  function foo(x, y)
    print(x + y)
  end
end

foo = function(x, y)
  print(x + y)
end<

At this point, calls to foo will do what was originally intended.

What exactly is loadfile doing?

Provided that the file you ask for can be found, and doesn't contain any syntax errors, all that loadfile does is return a new function, the body of which is the contents of the file. That is, the following call to loadfile:

loaded_chunk = loadfile("foo.lua")

Is equivalent to: (*)

loaded_chunk = function(...)
  --<< Contents of foo.lua here >>--
end

(*) As previously mentioned, they are not equivalent if foo.lua contains a syntax error, or cannot be read. Even exclusing these two cases, they are not technically equivalent, but for explanatory purposes, assume they are.

All the load functions (load, loadstring, loadfile, lua_load, luaL_loadbuffer, luaL_loadstring, and luaL_loadfile) work in the same way; they take some text, check it for syntax errors, and then either return an error or a function representing the given text. You can think of them as performing a similar role to the compilation step in C programming; they transform text into something executable, without actually executing it. Part of the confusion over loading Lua code comes from this executable thing being a Lua function, and said function (usually) containing other functions. Another common misunderstanding is mixing up the name of a file and the name of a function, and thinking that loading a file called foo.lua will return the function called foo from within that file. The filename of a loaded file is not used at all in the process of transforming text into something executable, and is only remembered for use in debugging information.

The role of globals in all this

For any Lua function, there are three ways to pass values in: globals, upvalues, and parameters. Likewise, there are three ways to pass values out: globals, upvalues, and return values (technically, we should be talking about environments rather than globals, and furthermore in Lua 5.2, environments are just upvalues and locals). When loading code, people often tend to forget about everything except globals. In our typical example, the output of foo.lua is a function which adds two values together and prints the result, and this is passed out in the form of a global variable called foo.

A commonly used piece of Lua syntactic sugar is the transformation of function foo into foo = function, which is another source of misunderstanding (noting that in turn, that is usually syntactic sugar for _ENV["foo"] = function in Lua 5.2, or something akin to _G["foo"] = function in Lua 5.0 and 5.1). What people read as defining a function is infact (usually) assigning a new instance of a function to a global variable / an entry in the table of globals. Hence loading a piece of Lua which "defines functions" doesn't result in those functions getting "defined", as loading said piece of Lua actually results in a function, which when executed, just makes some assignments to variables (albeit those variables generally being globals, and the values being assigned generally being functions).

Alternatives to globals

We could instead choose to make foo.lua pass this function out as a return value, in which case foo.lua would look like:

return function(x, y)
  print(x + y)
end

And usage of foo.lua would look like:

loaded_chunk = assert(loadfile("foo.lua"))
foo = loaded_chunk()
foo(2, 3)

On the other hand, we could make foo.lua itself be the function which takes two values and prints their sum, which would make foo.lua look like:

local x, y = ...
print(x + y)

Remembering that loading a chunk effectively wraps it in function(...), so the parameters are accessed via .... In this case, usage would be:

foo = assert(loadfile("foo.lua"))
foo(2, 3)

Another look at the typical example

When the typical example was introduced, it was stated that if you call foo a second time, then it'll start doing what was expected. Bearing in mind what has now been said, it should be clearer why this is the case. The first call to foo is infact calling foo.lua, which in turns defines a new global called foo, hence the second call to foo is calling a different function to the first call, this time calling the add-and-print function.

Also stated was that if on the other hand you replace loadfile with dofile, then Lua will complain with "attempt to call global 'foo' (a nil value)". Again, it should now be clearer as to why this is the case. First recall that dofile is a function which behaves roughly like:

function dofile(name)
  local loaded_chunk = assert(loadfile(name))
  return loaded_chunk()
end

In this case, the call to dofile would load and execute foo.lua, and this execution would define a global called foo, but this execution returns no values, meaning that dofile returns no values, meaning that foo = dofile("foo.lua") assigns no value (nil) to the global foo, thus overwriting the previously set foo.

The benefits of separating loading from executing

The above information states how things are, but it doesn't attempt to say why things are they way they are. Having a gap between loading a chunk and executing it has several advantages:

Loading with Lua's C API

The above has mainly been from the point of view of loading code from within Lua. If instead you're using Lua's C API, then things really aren't that different. lua_load and family do the same thing as load does; they collect some text, wrap it in function(...) --[[ text here ]] end, and push onto the stack either this new function, or a (syntax) error message.