Lua: How to avoid Circular Requires
Asked Answered
P

2

13

Problem

How can I avoid the following error from Lua 5.1 when attempting to do a circular require?

$ lua main.lua 
lua: ./bar.lua:1: loop or previous error loading module 'foo'
stack traceback:
    [C]: in function 'require'
    ./bar.lua:1: in main chunk
    [C]: in function 'require'
    ./foo.lua:1: in main chunk
    [C]: in function 'require'
    main.lua:1: in main chunk
    [C]: ?

File Structure

main.lua

require "foo"
require "bar"
print (Foo.getName())
print (Bar.getName())

foo.lua

require 'bar'
Foo = {}
Foo.name = 'foo'

function Foo:getName()
    return Foo.name .. Bar.name
end

bar.lua

require 'foo'
Bar = {}
Bar.name = 'bar'

function Bar:getName()
    return Bar.name .. Foo.name
end

Expected Output

$ lua main.lua 
foobar
barfoo
Paluas answered 20/12, 2012 at 3:16 Comment(1)
Closely related (but for Lua5.2, and avoiding globals): #8249198Olia
C
15

Another way would to solve this issue would be to change the structure of the code and extract the "mutual" functionality into a third module, which both Foo and Bar would require.

Childbearing answered 20/12, 2012 at 10:18 Comment(1)
Ultimately, this is certainly the approach I take which provides a much better dependency tree. In this case, I was curious about a solution which allowed circular dependencies. Thanks!Paluas
P
14

Solution

main.lua

Foo = Foo or require "foo"
Bar = Bar or require "bar"
print (Foo.getName())
print (Bar.getName())

foo.lua

Foo = {}
Bar = Bar or require "bar"
Foo.name = 'foo'

function Foo:getName()
    return Foo.name .. Bar.name
end

return Foo

bar.lua

Bar = {}
Foo = Foo or require "foo"
Bar.name = 'bar'

function Bar:getName()
    return Bar.name .. Foo.name
end

return Bar

Explanation

Since you are setting global variables, you can check to see if the file has already been required (aka; the global already defined) before attempting another require:

Bar = Bar or require "bar"

Your bar.lua would then have to return the definition of Bar;

Bar = {}
-- ...
return Bar

This wont entirely resolve the issue as bar.lua is expecting Foo to be defined. To resolve this, you can define a dummy variable with the same name:

Foo = {}
Bar = Bar or require "bar"

This is only possible because you are deferring the usage of Foo to when the function is called. If you wanted to call Foo.name from within the scope of bar.lua, you would end up with the same circular dependency issue.

Paluas answered 20/12, 2012 at 3:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.