Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

local VS global in lua

every source agrees in that point:

the access to local variables is faster than to global ones

In practical use, the main difference is how to handle the variable, due it's limited to the scope and not accessable from any point of the code.

In theory, a local variable is save from illegal alteration due it's not accessable from a wrong point and, even bette, to lookup the var is much more performant.

Now I wonder about the details of that concept; How does it technically work, that some parts of the code can access, others can not? How improoved is the Performance?

But the main question is: Let's mention I got a var bazinga = "So cool." and want to change it from somewhere. Due the string is public, I can do this easy. But now, if it's declared local and I'm out of scope, what performance effort is made, to gain access, if I handover the variable through X functions like this:

func_3(bazinga)
    func_N(bazinga)
end
func_2(bazinga)
   func_3(bazinga)
end

func_1()
  local bazinga = "So cool."
  func_2(bazinga) 
end

Up too wich point, the local variable keeps beeing more performant and why?

I ask you, due maintaining code in which objects are handed over many functions are getting a mess and I want to know, if it's really worth it.

like image 669
jawo Avatar asked Dec 25 '22 03:12

jawo


2 Answers

In theory, a local variable is save from illegal alteration due it's not accessable from a wrong point and, even bette, to lookup the var is much more performant.

Local variable is not save from anything in practical sense. This conception is a part of lexical scoping – the method of name resolution that has some advantages (as well as disadvantages, if you like) over dynamic and/or purely global scoping.

The root of performance is that in Lua locals are just stack slots, indexed by integer offset, computed once at compile-time (i.e. at load()). But globals are really keys into globals table, which is pretty regular table, so any access is a non-precomupted lookup. All this depends on the implementation details and may vary across different languages or even implementations (as someone already noted, LuaJIT is capable to optimize many things, so YMMV).

Now I wonder about the details of that concept; How does it technically work, that some parts of the code can access, others can not? How improoved is the Performance?

Technically, in 5.1 globals is a special table with special opcodes that access it, and 5.2 removed global opcodes and introduced _ENV upvalue per function. (What we call globals are actually environmental variables, because lookups go into function's environment that may be set to value other than "globals table", but let's not change the terminology on the fly). So, speaking in 5.2 terms, any global is just a key-value pair in globals table, that is accessible in every function through a lexically scoped variable.

Now on locals and lexical scoping. As you already know, local variables are stack slots. But what if our function uses a variable from outer scope? In that case a special block is created that holds a variable, and it becomes upvalue. Upvalue is a sort of seamless pointer to original variable, that prevents it from destruction when it's scope is over (local variables generally cease to exist when you escape the scope, right?).

But the main question is: Let's mention I got a var bazinga = "So cool." and want to change it from somewhere. Due the string is public, I can do this easy. But now, if it's declared local and I'm out of scope, what performance effort is made, to gain access, if I handover the variable through X functions like this: .....

Up too wich point, the local variable keeps beeing more performant and why?

In your snippet, it is not a variable that gets passed down the call stack, but a value "So cool." (which is a pointer into the heap, as all other garbage-collectible values). The local variable bazinga was never passed to any function, because Lua has no conception known as var-parameters (Pascal) or pointers/references (C/C++). Each time you call a function, all arguments become its local variables, and it our case, bazinga is not a single variable, but a bunch of stack slots in different stack frames that have the same value – same pointer into heap, with "So cool." string at that address. So there is no penalty with each level of call stack.

like image 110
user3125367 Avatar answered Jan 14 '23 16:01

user3125367


Before going into any comparison I'd want to mention that your worries are probably premature: write your code first, then profile it, and then optimize based on that. It may be difficult to optimize things after the fact in some cases, but this is not likely to be one of those cases.

Access to local variables is faster because access to global variables includes table lookup (whether in _G or in _ENV). LuaJIT may optimize some of that table access, so the difference may be less noticeable there.

You don't need to trade ease of access in this case as you can always use access from functions to upvalues to keep local variables available:

local myvar
function getvar() return myvar end
function setvar(val) myvar = val end

-- elsewhere
setvar('foo')
print(getvar()) -- prints 'foo'

Using getvar is not going to be faster than accessing myvar as a global variable, but this gives you an option to use myvar as local and still have access to it from other files (which is probably why you'd want it to be a global variable).

like image 29
Paul Kulchenko Avatar answered Jan 14 '23 15:01

Paul Kulchenko