If you have a modulescript named mymodule in workspace:
local tab = {}
tab.number = 3
return tab
If you require() this modulescript from two scripts, each one will receive the same return object, or in this case, the table named “tab”. This means any values stored within the table, such as “number” will be shared. So if in Script 1 I do:
Script 1:
tab = require(game.workspace.mymodule)
tab.number = 100
Now if in script 2 I do:
tab = require(game.workspace.mymodule)
print(tab.number) -- prints 100
This is because once the module has been required the first time, it runs the code in the module which creates tab, and the value 3 inside tab. When you require the same module a second time, the engine detects that this module has already been run before, so it doesn’t run the code again (or else tab.number would get reset to 3), but instead gives Script 2 the same return object (tab), which also happens to be the one affected by Script 1 changing tab.number to 100.
If you have script 3, script 4, etc all requiring this same module, they all get access to the same tab, so changing tab.number using any of these scripts would change the number for all these scripts.
Why do people say its “unsafe” to use _G? _G is similar to tab, except that all scripts automatically have access to this same table, even without requiring it. Let’s say I have a game with a “gold” coins, and also “gold” ore. If I have 2 scripts, one increasing the amount of “gold” coins on the server, and another stating how much “gold” is mined on the server
--Gold Coin Script
_G.gold = 0
while true do
wait(1)
_G.gold = _G.gold + 1000
end
--Gold ore script
_G.gold = 5
Oh no! Both my gold ore and gold coins are stored in the same place: _G.gold
If I have some other script that prints the number of gold ores mined, after 10 seconds it will print 10,000, not 5!
It’s pretty obvious here what went wrong, but for larger projects with 100s of scripts you could easily forget whether or not some spot in the _G table is already being used by another script.
With module scripts, if I really wanted to use this “gold” key, I could however many times I want, as long as each stored in a different table.
So if I have 3 scripts that do something with the number of gold ores, I would make a module like:
local GoldOreModule = {}
GoldOreModule.gold = 5
return GoldOreModule
Then all three of the scripts that require() this module can access the same table and same gold ore value.
Then in some different 3 scripts that mess with gold coins, you’d require this module:
local GoldCoinsModule = {}
GoldCoinsModule.gold = 100000
return GoldCoinsModule
These two gold values shouldn’t interfere, since they exist in two different tables, returned by two different modules. However I can still freely share some gold value across multiple scripts, as long as they require() the same module.
A note about client/server, for both the _G table and any tables returned by a modulescript, these objects do not cross the client server boundary. That means that in my original example with mymodule in workspace, if I required it with a localscript and changed tab.number to 1000, then required it with a server script, and did print(tab.number) on the server script, it would print 3. Tables can only be shared between different localscripts, or between different scripts, but not between scripts and localscripts and vice versa. There is a different _G table on every client from the _G table on the server.
Exploiters would only be able to change entries in the _G table for their own client, not other clients, and also not the server because all of these have individual _G tables.