Interesting read. I didn’t really know about _G until recently so I haven’t picked up any bad habits like using it instead of function parameters thankfully.
You say avoid using _G. Does that mean it would be ok to do things such as to define general isolated “pure” functions for use (IE Roblox Lua doesn’t have a math.round or math.lerp, would it make sense to define such functions in _G?) or would that still be bad practice?
I think that’s fine given it’s a very generic/broad helper function which isn’t doing something difficult to track/understand (like passing a global variable around that gets read from and modified in multiple scripts). Although, it’s possible to put those functions in a module script for that purpose too.
I just find it tedious to have many lengthy references at the start of my scripts to multiple modules nested deep in folders just to have basic features that more advanced engines come pre-built with such as the mindnumbing ability to lerp a float so that’s why I got excited when I learned of _G.
The less development time I spend doing the same thing over and over such as redefining basic functions or writing out lengthy require()s the better.
I had a thought when I came across this thread again after a while. Using _G is said to be terrible because using variables in the global scope can result in them being unpredictably modified by methods. I was going to ask this and Noobot9k had beat me to it already to some degree, but what if we’re dealing with values that are read only?
Say I have a script that requires several module scripts. Each module script requires the same service. Instead of getting the service over and over again and assigning it to a short variable in each script, couldn’t I simply make those service variables global? I’m sure that I could call that service directly and even declare the service once at the top of the script and then pass it to the module script functions as an argument but would using _G here be any worse?
The thing is, you would have to ensure that whatever code you wrote to put those service variables into _G ran before anything else that uses that service variable. You could do this by putting loops to check if the service variable has been instantiated in every script that uses it, but that’s no better than a simple require.
You wouldn’t need loops to check to see if the variable is declared if the script runs first, yes, but if you’re going to assign the service to a variable at the top of the script then pass it to the module scripts as an argument, _G should work better. A module script must be required before the code inside it can be run from a script and using _G on lines before the script is required would almost certainly work if only one script is requiring those modules.
Some people prefer to compartmentalize their code if it becomes too complex.
I’ve thought about that a lot. If you ask me, using global for constant values that are read-only doesn’t sound like a bad idea (though as mentioned you have to make sure the code that assigns it runs first)
It strikes me as the same kind of use as putting “pure” functions in there. Not much can go wrong if there’s only one place that could be defining it so you won’t end up with any run-away errors whose origin can’t be easily tracked.
One thing I don’t think was mentioned but I think could be an excellent use for the _G variable, is using the _G variable to create custom parts within your game. I could be wrong here but it seems like a good way of doing it.
Yes. You can already access the LocalPlayer conveniently as a property of the Players service across any LocalScript. If you have a framework, you can store a reference to the LocalPlayer in your framework table when it’s passed around/attached to other code. There’s virtually no need to use _G for this.
Still no because LocalPlayer isn’t set on the server and shared/_G don’t replicate across environments. If the server needs to interact with a player there’s a good chance your system will be able to give the player over or you can index them in the Players service directly by name or otherwise.
Never. There is never a case where you need to, should or should want to use _G. Only very old games may encounter situational cases where it’s useful to expose something to _G and they don’t have the capacity to fully rework systems (yet). New work will never have this problem and as such should never be using _G. ModuleScripts cover every use case _G originally had and can be better tailored for your game’s structure.