Posted on by

globals-featGlobal variables and functions are risky and there are a few crucial things you should know about them before you consider it safe to add one to the _G table, Lua’s “global table.”

Let’s quickly discuss the _G table. In Lua, variables that are all uppercase and prefixed by an underscore are considered private variables for Lua’s use, for example, _VERSION. You should not attempt to use these in your program under any circumstances. Well, notice that _G is uppercase and prefixed by an underscore as well! This means that it’s a reserved structure for system use.


But it’s so convenient!

It’s true: global variables and functions are convenient. By using the _G table, you can create a variable that’s accessible from both main.lua and any module, for example a Storyboard scene. But here’s the dirty little secret…

myVariable = 10
_G.myVariable = 10

…are exactly the same. In other words, Lua puts every global variable into the _G table, and everything you explicitly put in _G is available by its variable name:

_G.myVariable = 20
print( myVariable )
--you get a 20 printed in the console log

So why do some people tell you to put things in the _G table? Well, one reason is to clearly identify that you’re declaring a global variable, as opposed to a variable that you meant to be local but simply forgot to prefix with local.


No harm = No foul?

Some people have reported in the Corona Forums that they can print variables to the console, but Corona’s error and warning messages have stopped functioning. The likely cause of this was that the user created a global variable named debug — i.e. _G.debug. This effectively “trashed” access to an internal library that Corona uses to output debug messages.

If you print out the _G table on an empty main.lua using the following method…

for k,v in pairs( _G ) do
   print( k .. " => ", v )
end

…you can see all of the things already present there:

_G => table: 0x10d510f90
_VERSION => Lua 5.1
_credits_init => function: 0x108647cf0
_network_pathForFile => function: 0x101394180
al => table: 0x10868cc50
assert => function: 0x10868f3a0
audio => table: 0x108635da0
collectgarbage => function: 0x10138e7f0
coronabaselib => table: 0x10863b5f0
coroutine => table: 0x1086903b0
debug => table: 0x10136f730
display => table: 0x1013eb150
dofile => function: 0x10865e510
easing => table: 0x10138b600
error => function: 0x10865e540
gcinfo => function: 0x10865e570
getfenv => function: 0x1086a7f50
getmetatable => function: 0x10134d250
graphics => table: 0x108675420
io => table: 0x1013ef390
ipairs => function: 0x1013d2aa0
load => function: 0x10868fc90
loadfile => function: 0x10868fc30
loadstring => function: 0x1086b2ab0
lpeg => table: 0x10862c4d0
math => table: 0x10864a840
media => table: 0x1013d1a20
metatable => table: 0x10868caf0
module => function: 0x1013e0fd0
native => table: 0x1086559b0
network => table: 0x101393b40
newproxy => function: 0x108617180
next => function: 0x1013ec010
os => table: 0x10131c900
package => table: 0x10863fc10
pairs => function: 0x1013d9870
pcall => function: 0x1013ec040
print => function: 0x10863b660
rawequal => function: 0x1013c79a0
rawget => function: 0x1013c7a00
rawset => function: 0x1013e7ab0
require => function: 0x10138fbc0
select => function: 0x1013e7ae0
setfenv => function: 0x1013e7b10
setmetatable => function: 0x10134a3f0
string => table: 0x101311df0
system => table: 0x1013b2e60
table => table: 0x1013ad550
timer => table: 0x10138a550
tonumber => function: 0x10134a450
tostring => function: 0x1086067f0
transition => table: 0x10138e000
type => function: 0x10130ffb0
unpack => function: 0x10130ffe0
xpcall => function: 0x101310010

All of the APIs listed in the API Reference under the (globals) entry are here, as well as some undocumented items like debug and several core API groups like math, string, and audio. With this in mind, you might assume that you can write code like this:

_G.audio = true  --play audio if true, don't play if false
_G.type = "Gold"
_G.timer = timer.performWithDelay( 1000, doSomething )

However, what you’ve done is “trash” these Corona libraries, so you won’t be able to play audio or use the type() function — and that timer isn’t going to time anything!


“So I won’t use those global names…”

Not so fast! These are the libraries that you shouldn’t overwrite today, based on a completely blank main.lua file. The list above assumes that you haven’t require’d any additional libraries or modules, whether they be Corona libraries like physics, your own modules, or third-party libraries like director. In addition, other things may slip into the global space that you’re simply not aware of. Finally, as we roll out new features and libraries, we might use a global term that you’re currently using, in which case upgrading to a new version of Corona SDK would suddenly conflict with your app.


Simply put: Don’t use globals!

“Wait,” you may plead, “I still need to access something that I haven’t declared yet, or access variables between modules.” Fortunately, both of these are easy to accomplish without using globals.

The first case — accessing something you haven’t declared yet — is solved by the forward declaration method. As a Lua/Corona programmer, understanding scope is essential. If you need to use a variable (usually a function) before you declare it, simply set a variable and use the alternate function declaration syntax:

local doSomething  --forward declaration

local function makeSomethingHappen()
   local fred = 10
   doSomething( fred )
end

doSomething = function( param )
   print( param )
end

At the end, we just assign the function that does the work to the variable doSomething. In this way, the makeSomethingHappen function becomes aware of the doSomething function since it was declared “above” the code chunk which requests it.

And to solve the second case — accessing variables between modules — you can simply create a Lua file named mydata.lua (or similar) with the following contents:

--my global space
local M = {}
return M

Then, in each of your Lua modules, simply require the module as follows:

local myData = require( "mydata" )

Now you can use the myData table just like you would _G and circumvent the risk of overwriting things in the _G table, as well as avoid the general issues and pitfalls that come along with globals.

myData.myVariable = 10

In summary

We’ve been stressing the “avoid globals” stance for a long time now, and as you can see, there is essentially no further need for global variables or functions. With careful scoping and management of the internal _G table, you can accomplish everything you need without them.

Questions or comments? Please contribute to the discussion below.


Posted by . Thanks for reading...

37 Responses to “Tutorial: Goodbye Globals!”

  1. Mario Roberti

    Excellent tutorial. It makes perfect sense now. And there really IS no excuse not to use a separate lua file to hold all my goodies.

    Thanks a lot!

    -Mario

    Reply
  2. Kerem

    Great tutorial as usual. Its so easy to rely on Globals in head down quick and dirty programming mode but it gets ugly real quick as your project grows. I will implement the myData.lua right away. Thanks much!!!

    Reply
  3. Kerem

    Follow-on question… Which is better

    To put the following as globals in your main.lua

    require “sqlite3″
    require “storyboard”
    require( “widget” )

    or the following in each module including main.lua

    local sqlite3 = require “sqlite3″
    local storyboard = require “storyboard”
    local widget = require( “widget” )

    Any performance tradeoffs in declaring the modules and requiring locally?

    Thanks.

    Reply
  4. Rob Miracle

    You should always do the “local” thing. There is zero benefit from doing it the other way that I’m aware of.

    Reply
  5. Mo

    Just to make sure: how would you set variables under myData?
    Something like

    local M

    musicFlag = true
    test = 10

    Return M

    And use it in another module as:

    Print (M.test)

    Correct?

    Thanks.
    Mo

    Reply
    • Andreas

      Hi Mo,

      you would use:

      –my global space
      local M = {}

      M.musicFlag = true
      M.test = 10

      return M

      Best,
      Andreas

      Reply
  6. Lerg

    Good point. But having one global “MyData = {}” in your main.lua is totally legit. Saves you time on writing “local MyData = require(‘mydata’)” each time. Or you can require this module as global again in main.lua if you want to store some variables in a separate file.

    Reply
  7. Rob Miracle

    @DaveBaxter, I have used that concept for most of my apps as well. Keep in mind that a future update might use storyboard.state in a different way. That variable may not be protected in the future. In fact I was adding an attribute of my own to storyboard and an update nailed me. I forget which one, maybe .debug. This way, you are not touching any existing API space. And for those that want a quick Search and Replace:

    local _myG = require(“mydata”). Just like _G that you’re used to, just puts the letters “my” in front.

    @Lerg, yes, it saves you having to type that line several times, but in that case myData will be inserted into _G since it’s global and has the potential to overwrite someone else whose using the same technique (if you use any 3rd party solutions). Besides, data that exists in global space is referenced differently than local space and global space is much more resource costly to reference. This is why we tell you to localize things like the math library. Basically globals are looked up in a hash, where frequently locals are either in registers or found by index (a quicker operation).

    We can’t stop you from using globals that way, but …

    Reply
  8. Lerg

    @Rob yeah, 3rd party code is often not pretty. If it’s something small I just refactor and clean it on my own. So far had no need to use some really big 3rd party modules. The largest would be twitter+oauth and key encryption/decryption modules.

    As for speed advantage it’s not really matters as long as you don’t access it several hundreds or thousands times on an event. If you do access it a lot you would better have it cached in the current function anyway for the best results (local MyVar at the top of a module is not enough), so again not a big difference of use or performance.

    Lua only has a partial performance impact itself. The biggest impact is on the renderer. It’s more important to optimize graphics rather than cache some variables. Not to tell how entire algorithms often may be optimized to gain significant boost.

    Also I do store all my libs and corona libs (storyboard, audio, widget) as globals. For me the clean code is more important than those few milliseconds you can save on some events.

    Well, yeah, the only thing I want to point out is that using globals is not evil as long as you know what are you doing. For novices the general advice would be to avoid _G of course.

    Reply
  9. J. A. Whye

    Bah, humbug!

    I think a completely valid thing would be for Corona Labs to prefix their use of globals (kind of a namespace-type thing) so the chances of me or anyone else bumping into them is pretty much nil.

    Because I think for “audio = true” in main.lua to screw up the actual SDK means Corona Labs did something wrong, not whoever wrote that line of code.

    How about you guys use _G.CoronaLabsAPI = {} and throw everything in there? Then there’s only one thing we have to stay away from and future features won’t break our code, etc.

    I understand there are performance reasons to avoid globals, but breaking the SDK as a reasons seems kind of wobbly.

    Jay

    Reply
  10. Rob Miracle

    Jay, name spacing would be great, but using your example you would have to make every api call like:

    CoronaLabsAPI.display.newImageRect()

    Prefixing every API call with the name space would get tiring on programmers in a hurry.

    Reply
    • J. A. Whye

      Okay, but that was just off the top of my head. You guys are all smart, someone come up with a better solution than mine — one that’s not, “Don’t use globals.” ;)

      Jay

      Reply
  11. Paolo

    Nice tutorial, I find useful the idea of looking into _G for potential compatibility problems. Just for sharing my practice, I use very few globals in non performance critical bits such as music and app state (which view and tab is the user on and so on) and I name those variable in such a way that any accidental override would be unlikely (e.g. bgMusicAGlobal or currentViewGlobal). For the rest I decide which module owns a variable (it is usually the module that creates the variable) and use that module M table for storing. The idea of pooling some variables in one module is interesting because it saves the pain of remembering which module own which variable.

    Reply
  12. Dave

    My favourite part is “..oSomething. In this way, the makeSomethingHappen function becomes aware of the doSomething function since it was decla..”

    Made me happy =]

    Dave

    Reply
  13. JonPM

    Is there a significant performance difference by using the mydata.lua method vs globals? Or is that simply to avoid “trashing” the predefined libraries?

    Reply
  14. Rob Miracle

    Globals are the slowest to access variables in Lua. Members of a local table are faster. The word: “significant” is important here. If you’re setting up a one page utility app with a couple of buttons and fetching some data from a web service that updates once an hour? Then it’s insignificant. You’re moving a thousand bullets around the screen? It’s probably significant.

    Performance is only one factor. Not trashing your own code is just as important as not trashing the predefined libraries. I can’t tell you the number of storyboard examples where they create:

    background = display.newImageRect(“background.png”, 570, 360)

    in one scene, they to another and execute the same line of code and you got yourself a memory leak. Or they go back to the previous seen without purging and wonder why the background image didn’t change.

    Or people who use other people’s libraries and each other’s globals stomp on each other.

    If you know what you’re doing, and you name space them accordingly and you are not in a situation where performance counts, then use them… You know what you’re doing. But I would ask, why would you want to use them? Since you need to namespace them to avoid conflicts, that means typing some prefix on the variable name, why not make that namespace “mydata.” Want to type even less? How about myG. That’s just one character more than _G.

    Reply
  15. Leo

    Hi there,

    I’m new to Lua and working on my project. Disclaimer: I’m using the physics game with the falling box as a starting point and adapting that code.

    So I tried implementing a “player.lua” file to contrain general information regarding my player character (image locations, stats, etc). I wanted to make it accesible across my different “levels”, so this seemed like the way to go. However, I’m having a weird error regarding passing a string of my picture name. My code is as follws:

    player.lua

    local playerData = {}

    playerData.playerImageLoc = “\”crate.png\””

    return playerData

    level1.lua

    local storyboard = require( “storyboard” )
    local scene = storyboard.newScene()

    – include Corona’s “physics” library
    local physics = require “physics”
    physics.start(); physics.pause()

    local playerData = require(“player”)
    local player

    ——————————————–

    – forward declarations and other locals
    local screenW, screenH, halfW = display.contentWidth, display.contentHeight, display.contentWidth*0.5

    —————————————————————————————–
    – BEGINNING OF YOUR IMPLEMENTATION

    – NOTE: Code outside of listener functions (below) will only be executed once,
    – unless storyboard.removeScene() is called.

    —————————————————————————————–

    – Called when the scene’s view does not exist:
    function scene:createScene( event )
    local group = self.view

    – make a player (off-screen), position it, and rotate slightly
    print(playerData.playerImageLoc)
    –player = display.newImageRect( playerData.playerImageLoc, 90, 90 )
    player = display.newImageRect( “player.png”, 90, 90 )
    player.x = display.contentWidth/2
    player.y = (display.contentHeight)/4

    – add physics to the player
    physics.addBody(player,”static”, { density=1.0, friction=0.3, bounce=0.3 } )

    group:insert( player )
    end

    The error says Corona can’t find the image, despite it existing. If I hard code that string, no error is thrown. Thanks for any advice you can offer.

    Reply
    • Rob Miracle

      Is there a reason you are putting quotes into the string. The file name doesn’t actually have quote marks in it does it? Try:

      playerData.playerImageLoc = “crate.png”

      Reply
  16. PixelPiledriver

    Yo.
    Thanks for the tutorial.

    I am a C, C++, C# programmer.
    Going thru the documentation and learning the differences between those and Lua.
    Good times so far.

    However I am having one issue.
    In C++/C# I am used to creating a class, and then an object from that class, and then using the . to reveal all of the available public members in intellisense.
    Something like this:
    ———————————
    public class Stuff
    {
    public int x = 1;
    public int y = 1;
    }

    public Stuff obj = new Stuff();
    obj. ————> from here intellisense will show [obj.x, obj.y] and I will select one.

    But in Sublime/Corona/Lua:
    ——————————————–
    ———–
    Stuff.lua
    ———–
    local s = {}
    s.x = 1
    s.y = 1
    return s

    ———–
    main.lua
    ———–
    local Stuff = require(“Stuff.lua”)
    Stuff. —————> there will be no suggestions from intellisense after the dot.

    However if I use one of the members:
    ————————————————-
    print(Stuff.x)
    Stuff. ——————> now intellisense will show [Stuff.x], but it will not show [Stuff.y], until after it is also used.

    Is there a way to see all of the members of a table in intellisense before using them?
    Or is that just part of how Lua works?
    This is something that I can become accustomed to, but it feels strange as I have to remember the members of a file, or look them up, the first time I use them.

    Anyways, thanks.
    Corona is really cool, and I’m enjoying the docs.

    Reply
  17. Nick

    Doesn’t work..!!
    All I get is “Attempt to index local..”
    “mydata.lua” is located in the same place as main.lua?
    I’ve written the simplest code..and it’s not reading the other file..please elaborate..?

    Reply
    • Rob Miracle

      Can you post this question in the forums? We are going to want to see some code and it doesn’t render well here in the comments.

      Reply
  18. johannes_lalala

    Dont tell the people to not use globals. There are things that just are global and would cause a lot of pain and errors by having to carry them through every function they are needed in.

    Why should your language setting or your click sound handle should not be global?

    Emulating globals by requiring a ‘myData.lua’ just adds unconvenience and more code that isn’t neccessary.

    So ‘Never use globals’ is as dumb as ‘Always use globals’, just use them with care and know the consequences.

    Reply
  19. Rob Miracle

    Hi Johannes, we may have to agree to disagree. This is like a goto statement. Its there, you can use it and there are some circumstances where it might make sense, but in 99 % of the circumstances, its worth the extra effort for code readability, sustainability and supportability if you do not. Globals fall into this case. You have no control over what happens in global space. You might right over something that’s already a global (set a variable called “debug” and watch your print statements stop working…). A 3rd party library might stomp on your usage. There are too many ways that globals can harm your program than the gains you get from using them.

    The only safe way to use globals is to namespace your variables so that other things don’t trump you. Some people might believe that using _G is that name space, but that’s not the case. _G.fred and fred are the exact same variable. If you want to name space your variable, you have to put some tag in the variable name, like perhaps:

    myglobal_score
    mygobal_width

    I doubt someone is going to use that name (though myglobal probably is less safe than gonzo_score….)

    By the time you name space your variables, you have in effect typed in enough extra work, that accessing it from a table is the same thing:

    myglobal.score
    myglobal.width

    The only trick is to require the table in each module and there are performance benefits from accessing the data in locally required table vs. global space.

    Sure, a seasoned programmer who knows what they are doing can make effective use of globals, just like that “goto” statement, but generally speaking, it’s bad form, hard to support in the long term, poor performing and simply dangerous in creating hard to find and fix bugs.

    Rob

    Reply
    • johannes_lalala

      Hey Rob,

      Sure, you’re right with the namespace pollution argument and the performance of locals. A collegue of mine once wondered why everything was broken because he used a global variable named ‘object’ :)

      But you can name things like _focus or FOCUS. Often the things that just are global are also things that are needed often, so it’s tedious to always have to write myglobal.var, so myglobal will eventually turn into glob.var, or g.var and that’s the point where we could just have used a properly named global variable. (and personally I dislike the dots everywhere)

      Lua’s strength is building small things fast, because it doesn’t force oop and it’s bloatedness or any other strict structure onto us. We don’t build big software that’s hard to maintain with big developer teams.
      And often, certainly not always, less code (with less structure) is easier to understand and to maintain.

      Not long ago I would also never even think about introducing a global variable. I had to actually lern a little bit of ‘sloppyness’, now my life is better. Some programmers have to learn strictness, some have to learn sloppyness. Globals are there for a reason and I think sometimes they are the adequate tool.

      so agreed :)

      Reply
  20. Edwin

    Do I need to manually clean up the myData table in myData.lua or does the system automatically clean it at some point?

    Thanks

    Reply
    • Rob Miracle

      There is no automatic cleanup of myData. What you put in the table, you are responsible to clean up. That said consider this:

      1. Most of the data you are going to put into that table is pretty small if you’re not referencing display objects or audio. The numbers, strings and booleans and other small tables you might add, isn’t a huge hit on memory.

      2. If you do put in display objects and you are using a scene manager like Composer (or it’s older brother Storyboard) and those objects are also in the scene’s view display group, then they will be cleaned up as well.

      Rob

      Reply

Leave a Reply

  • (Will Not Be Published)