Difference between revisions of "local"

 
(2 intermediate revisions by 2 users not shown)
Line 10: Line 10:
 
* '''globals are unknown''': globals are mutable, which means you don't know what has modified it, or when. If you're aware of it, then you'd have to perform many checks whenever you wish to use it or modify it, which just adds work, not reducing it
 
* '''globals are unknown''': globals are mutable, which means you don't know what has modified it, or when. If you're aware of it, then you'd have to perform many checks whenever you wish to use it or modify it, which just adds work, not reducing it
 
* '''globals promote bad design''': Since they're so easy to access, globals generally get loaded with a bunch of stuff that is unrelated. globals generally indicate "spaghetti" code - code that seems to do everything, but none of it well, and whenever you go to edit it, it's a nightmare.
 
* '''globals promote bad design''': Since they're so easy to access, globals generally get loaded with a bunch of stuff that is unrelated. globals generally indicate "spaghetti" code - code that seems to do everything, but none of it well, and whenever you go to edit it, it's a nightmare.
* '''locals are fast''': Without going into too many details, ''locals are faster in Lua''. Every global is stored in the <code>_G</code> table, and whenever you go to access one, Lua has to go hunting into this table to find it. Locals, however, are stored on 'registers', which makes them super fast to access. Adding two <code>local</code> numbers takes a single stack instruction, [https://www.lua.org/gems/sample.pdf|but adding two globals might take up to four!] A program chock-full of globals could be markedly slower than one with locals.
+
* '''locals are fast''': Without going into too many details, ''locals are faster in Lua''. Every global is stored in the <code>_G</code> table, and whenever you go to access one, Lua has to go hunting into this table to find it. Locals, however, are stored on 'registers', which makes them super fast to access. Adding two <code>local</code> numbers takes a single stack instruction, [https://www.lua.org/gems/sample.pdf but adding two globals might take up to four!] A program chock-full of globals could be markedly slower than one with locals.
  
 
== When should I use globals? ==
 
== When should I use globals? ==
Line 22: Line 22:
 
* much safer (no other code is touching and changing the variable without your knowledge).
 
* much safer (no other code is touching and changing the variable without your knowledge).
 
* promotes better program structure (by not cluttering up the global namespace).
 
* promotes better program structure (by not cluttering up the global namespace).
* and above all else [http://lua-users.org/wiki/OptimisingUsingLocalVariables|a very easy optimisation] to make early on.
+
* and above all else [http://lua-users.org/wiki/OptimisingUsingLocalVariables a very easy optimization] to make early on.
  
 
That doesn't mean you should forbid all use of globals, just when you use them, be conscious of what you're using them for.
 
That doesn't mean you should forbid all use of globals, just when you use them, be conscious of what you're using them for.
Line 84: Line 84:
 
== See Also ==  
 
== See Also ==  
 
[http://www.lua.org/pil/4.2.html Programming in Lua]
 
[http://www.lua.org/pil/4.2.html Programming in Lua]
 +
 +
== Other Languages ==
 +
{{i18n|local}}

Latest revision as of 21:54, 17 August 2024

In Lua, variables can be global or local. Unlike global variables, local variables have their scope limited to the block where they are declared.

What?

In many common programming languages, they infer the scope of your variable from where you put it in your code (ie. declaring a variable in a function means that you can only see said variable in that function), or require explicit modifiers put on declarations that specify public or private access (like in Java). By default in Lua, your variables are in the global scope, unless you define them with the local statement

A variable or function declared with the `local` statement restricts their scope to the block they're declared in. If you declare a local at the file level, then that value is only visible to that file, same for when you declare values within a function.

Using local is beneficial because:

  • globals are unknown: globals are mutable, which means you don't know what has modified it, or when. If you're aware of it, then you'd have to perform many checks whenever you wish to use it or modify it, which just adds work, not reducing it
  • globals promote bad design: Since they're so easy to access, globals generally get loaded with a bunch of stuff that is unrelated. globals generally indicate "spaghetti" code - code that seems to do everything, but none of it well, and whenever you go to edit it, it's a nightmare.
  • locals are fast: Without going into too many details, locals are faster in Lua. Every global is stored in the _G table, and whenever you go to access one, Lua has to go hunting into this table to find it. Locals, however, are stored on 'registers', which makes them super fast to access. Adding two local numbers takes a single stack instruction, but adding two globals might take up to four! A program chock-full of globals could be markedly slower than one with locals.

When should I use globals?

All of this doesn't mean you shouldn't use Globals. In fact, if you're learning how to program, it's probably more than you have to worry about, however, if you're starting out in Lua, and you're already familiar with the idea of scopes from, say, C# or Java, then you're already halfway there.

Globals are useful in a handful of situations, however by introducing one, you should be strict on what you do with it. For example, only read from a global, don't modify any of its internal state. Don't overload your globals with functions and variables because it's "easy" - take the time to tie your program together properly (future you would love you for it).

TL;DR

In a nutshell, elect to use local over global declarations as it's:

  • much safer (no other code is touching and changing the variable without your knowledge).
  • promotes better program structure (by not cluttering up the global namespace).
  • and above all else a very easy optimization to make early on.

That doesn't mean you should forbid all use of globals, just when you use them, be conscious of what you're using them for.

Example

-- ===================================================================
-- File: "locals.lua"
-- ===================================================================

local LocalTest = {}

Global = "This is a global variable"
function GlobalFunction()
  print("This is a global function")
end

local localVariable = "This is a file-scoped local variable"

local function localFunction()
  local localFunctionVariable = "This is a function-scoped local variable"
  local localTable = { "This is a value in a table" }
  print("This is a local function")
  print(Global)                 -- prints "This is a global variable
  print(localVariable)          -- prints "This is a file-scoped local variable"
  print(localFunctionVariable)  -- prints "This is a function-scoped local variable"
  print(localTable[1])          -- prints "This is a value in a table"
end

LocalTest.exposedVariable = "This is an exposed, non-global variable"

function LocalTest.exposedFunction()
  print("This is an exposed function from Local Test")
  print(Global)                 -- prints "This is a global variable
  print(localVariable)          -- prints "This is a file-scoped local variable"
  print(localFunctionVariable)  -- prints "nil"
  print(localTable[1])          -- throws an error
end

return LocalTest

-- ===================================================================
-- File: "main.lua"
-- ===================================================================

local locals = require "locals"

print(Global)           -- prints "This is a global variable"
print(GlobalFunction()) -- prints "This is a global function"

-- Note how we have to say "look in the imported `locals` file for `exposed` variables
print(locals.exposedVariable) -- prints "This is an exposed, non-global variable"
print(exposedVariable)        -- prints "nil"

-- Both of these blow up, which means the second will never get called.
print(locals.exposedFunction())    -- throws and error with "attempt to index global 'localTable' (a nil value)"
print(locals.localFunction())      -- throws an error with "attempt to call field 'localFunction' (a nil value)"

See Also

Programming in Lua

Other Languages