4

This is a small question related to the answer given here, https://tex.stackexchange.com/a/201742/17858 which computes the factorial of a number in an external lua file.

\documentclass{article}

%\directlua{dofile("luatest.lua")}
\directlua{require("luatest.lua")}
\newcommand*{\myluafact}[1]{%
  \directlua{tex.write(fact(#1))}%
}
\begin{document}
  test \myluafact{5}
\end{document}

The code for computing factorial is in luatest.lua again copied from the same link above

function fact (n)
  if n == 0 then
    return 1
  else
    return n * fact(n-1)
  end
end

The results from using dofile and require are identical on my machine for this particular example.

Is there any technical difference between loading external lua files with require or dofile in general?

  • require is cached, dofile isn't. Therefore you are guaranteed to always get the same handle of a module from require. – Henri Menke Dec 10 '18 at 5:24
4

tl;dr require is cached, dofile isn't.


In contrast to dofile, require caches which files have been requested already. For example, if you load a module example

local example = require("example")

Lua will add the handle that was returned from example to an internal table called package.loaded. If your application calls require("example") again, Lua will not load the example module again, but simply return the handle which was cached in package.loaded.

This approach also shows why it is a bad idea to define global variables in a file which is supposed to be used as a module. The luatest module from your question just defines the global name fact but does not return a handle. Therefore the Lua interpreter can't cache it and if something redefines the global name fact there is no way to get the original back. Another issue with global names is, that they tend to collide. Imagine you had a second module which also defined the fact global name. Which one is Lua supposed to take?

In principle you could use dofile for files which you strictly only load once and where all the names defined within are unlikely to collide. Personally, I prefer modules even for this situation because it reduces interdependencies and makes things reusable in other contexts.

You should restructure your example:

luatest.lua

local function fact(n)
  if n == 0 then
    return 1
  else
    return n * fact(n-1)
  end
end

return { fact = fact }

test.tex

\documentclass{article}

\directlua{luatest = require("luatest")}
\newcommand*{\myluafact}[1]{%
  \directlua{tex.write(luatest.fact(#1))}%
}
\begin{document}
  test \myluafact{5}
\end{document}
  • 1
    isn't it the case that (unless you reset the package.loaded table) then require won't run the same file twice (if passed the same virtual filename) so even in the OPs original version with fact a global name, if you do require("luatest.lua") twice then essentially nothing happens on the second call, and if fact has been redefined in between the calls that redefinition will be in force as the second require will not re-load the definition? – David Carlisle Dec 10 '18 at 9:23
  • @DavidCarlisle That is probably true. I'd have to read the Lua docs for package.loaded again. My answer is just reconstructed from memory. – Henri Menke Dec 10 '18 at 9:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.