Why is it bad practice to use _G?

I know there is a lot of questions regarding the same thing, but I feel like some of my questions were unanswered.

In my games, if I want to call a module, I don’t want to repeat the same thing:

local module_name = require(game:GetService("ReplicatedStorage"):WaitForChild("modules"):WaitForChild("misc"):WaitForChild("network"))

I thought of just simply doing this

local module_name = _G.network

But I’ve been told by many that using _G is bad practice, and I want to know why? Because, I only want to use this to call modules faster.

1 Like
local myModule = require(game.ReplicatedStorage.modules.misc[“network”])

No need to use :WaitForChild when calling a module, as it doesn’t need to be loaded in order to be executed.

2 Likes

wait, so if the modulescript instance doesn’t exist, i can still call it?

If it doesn’t exist then it will do everything else that doesn’t exist; throw an error if called. Or, it will be silence and doesn’t work. Depends on how it’s called though.

2 Likes

thats why i used waitforchilds, cause if it throws an error, then the whole script won’t run

1 Like

That’s bad practice, because if you use it, and it doesn’t find the object, it will yield until the object exist, which in the long run can be exhausting for the engine and could result in issues between other scripts.

1 Like

what, it’s bad practice because it doesn’t error, unlike your solution to not use waitforchild?

i would say using _G the way you’re proposing is bad practice because _G is different on every Actor lua state. i have a feeling you aren’t using actors, and neither are the people telling you that _G is bad practice. if that’s the case, they’re wrong, and using _G like in your example is not bad practice, that would be like saying the Knit framework is bad practice. the truth is that your use of _G defines the practice of your game, much like Knit dictates what good practice is for games that use it.

1 Like

Mostly for 2 reasons. It’s slower to access variables that are in the global space (local variables are much faster to read/write). Also as a rule of thumb, all variables should exist in the narrowest scope possible. This just helps you not have headaches down the line with naming collisions and stuff as well as making it clear what variables are intended to be used where.

Basically g is a table lookup where a direct value is a reference. A table lookup is slower, but to be clear the speed is rarely ever the reason this should be avoided (only in a super tight loop it matters). It’s more the namespace conflicts and the general headaches related to shoving too many unrelated things together under 1 name.

While this is somewhat true, it’s heavily context dependant. If the module is ensured to be loaded and doesn’t exist, that is certainly a problem. But often if a module doesn’t load, most code realistically can’t recover from it anyways as you loose a ton of functionality.

If you can recover after failing to load a module, or if the module is optional, you could always make the wait for child time out and just check if it was found before attempting to require it. Or load it asynchronously, but this is often overkill.

1 Like

Its not, _G is basically a global table accessible from all server sided scripts and its not slower or less efficient than a table definied in a same script its being used in, for some reason people think that _G is some kind of magic table which is not true you can use it and it will be fine, the only down side of _G is that its hard to debug scripts when you have a lot of values in it and each value is being set from different script

thanks for the responses!!! i have one final question, i want to use _G but like this:

local getlib = _G.getlib
local network = getlib("network")

is this also a better way because it’s a read-only kind of thing?

You really should just put “network” in its own module script, and then just require it normally. The main pro is auto correct.

it’s already in it’s own module script, the global function’s purpose is to require it without having to chain a bunch of getservices n waitforchilds