Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

I Need To Recurively Require Modules, How?

I have two module scripts

Angle

local Vector = require(script.Parent.Vector).Vector

local globals = {} 

local ANGLE = {}
ANGLE.__index = ANGLE

function globals.Angle( p, y, r )

	return setmetatable( { tonumber(p) or 0, tonumber(y) or 0, tonumber(r) or 0 }, ANGLE )

end

--[[---------------------------------------------------------
	Returns a normal vector facing in the direction that the angle points. 
-----------------------------------------------------------]]
function ANGLE:Forward()

	return Vector(math.cos(self[2]) * math.cos(self[1]), math.sin(self[2]) * math.cos(self[1]), math.sin(self[1]))
	
end

return globals

Vector

local Angle = require(script.Parent.Angle).Angle

local globals = {} 

local VECTOR = {}
VECTOR.__index = VECTOR

function globals.Vector( x, y, z )

	return setmetatable( { tonumber(x) or 0, tonumber(y) or 0, tonumber(z) or 0 }, VECTOR )

end

--[[---------------------------------------------------------
	Returns an angle representing the normal of the vector. 
-----------------------------------------------------------]]
function VECTOR:Angle() --TODO
	
	return Angle()

end

They need to be required recursively but you cant do that in roblox. What do I do?

1 comment

0

You can do anything in roblox, also im a bit confused, what r u trying to do?

1 answer

✓ Accepted answer

What you are trying to do is called circular dependency, this is bad bad, you should improve your module structure to avoid it, but it might be difficult, and if so, what you asked for can be done by using third module which is going to store the data that should be shared across the modules, and both Vector and Angles are going to require it without having to require each other.

The only problem is that requiring other modules before the module hit return is unsafe since we don't yet know what content will current module have, in frameworks people create function for each module (often called init), then they preload all modules into a table and then after all modules are ready they call the function in every module, when this function is executed, the module knows for sure that all of the other modules are ready and can start relying on them or execute some code.

However, for a simpler version you can use custom require function which will avoid circular dependency like this:

  1. Module A requires module B

  2. Custom require creates empty table for module A inside of some table

  3. Module B requires module A

  4. Custom require creates empty table for module B inside the same table

  5. Custom require sees that module A has a table inside of the table meaning it has already been required, it returns that table without requiring the module again, for now the table is empty.

  6. Module B hits return and custom require replaces the empty table it previously created into return value of module B

  7. Module A hits return and custom require replaces the empty table it previously created into return value of module A

I made it look complicated, you better see the code, it's few lines, this logic has 1 drawback and that's that you can't use contents of the module you circularly require outside of a function.

req (ModuleScript)

local required_modules = {}

local function req(module)
    local existing = required_modules[module]

    if existing ~= nil then
        return existing
    end

    -- Next time this same module is required before it returns, this
    -- placeholder table will be used instead of requiring the same module
    -- again to prevent circular dependency
    required_modules[module] = {}

    local new = require(module)

    -- Fill empty table with contents of the required module
    for key, value in pairs(new) do
        required_modules[module][key] = value
    end

    return required_modules[module]
end

return req

Angle

local req = require(path.to.req)

-- For now this will be `{}` but after `Vector` hits `return` it will
-- be filled with its contents
local VectorGlobals = req(script.Parent.Vector)

function globals.Angle()
    -- at the time this function is called you can be sure that
    -- `VectorGlobals` is ready to be used
end

-- outside of functions you may not use `VectorGlobals` since this
-- module might be loaded if it does not require any other
-- modules, but will not, be loaded if it requires this module

return globals

Same logic with Vector module, you can see it's actually not that bad, however, avoiding circular dependency is going to make your structure far better. In your case you could merge your modules into single one since they do practically the same.

7 comments

0

I normally avoid circular dependancy but I'm porting gmod's lua code to roblox and that has alot of it. The alternate require method seems like what gmod might even have done, so thats what ill do.

0

I implemented it but it still seems to give me a "Requested module was required recursively" error when its required inside the req function.

0

did the non-module script require 'Vector' and 'Angle' modules using the 'req' function?

0

oh also i was showing the 'req' function as a simple example, in practice i don't recommend using it since it will waste memory by copying contents of every module, instead try something like this https://gist.github.com/kiruda/31862bb9c612d55c81120323fbb73925

0

the way ive got it is there is one non-module script that requires "gluafenv" gluafenv requires both Vector and Angle and combines them in a table and returns that. Then in the non-module script I use setfenv, and then call Vector or Angle.

0
0

may i see the code please W_W

This discussion is preserved as it was. New answers, comments, and votes are closed.