So I'm reading this book about Lua and it says it's good practice to use local variables over globals but it doesn't say why. So my question is, why is it better? Especially when a local variable would need 4 lines of code while a global only needs 2 :confused:
Oh I see now, thanks. But I'm still not convinced why local variables are better than globals, how exactly are they "faster" than globals?
Locals are stored on the function call stack and are released when the function returns to the caller.
Globals are stored in a _G[] global table which is stored on the heap.
Accessing a local "myVar" is just reading it from memory off the stack.
Accessing a global "myVar" tells Lua to perform a table lookup on _G to find the value of _G["myVar"].
A function or file scope chunk can have up to 200 locals defined.
The first is of a magnitude faster than the second. Hash table lookups ARE SLOW and are NOT CONSTANT TIME. The larger the table, the more time it takes to find it.
All Lua code from all addons share the same global namespace _G. So if your addon used the global variable "myVar" and another addon also happen to use that exact same global variable "myVar", those 2 addons would likely kill each other.
At the top of many addons, you would see code like
local pairs = pairs
The reason is simply to create a local variable called "pairs" that points to the same function as the global _G["pairs"].
Oh, hmm interesting, I had no idea local variables were stored in the stack and globals in the heap. I will definitely use local variables whenever I can. I still have a lot to learn but this helped a lot, thanks all :)
MyAddon = LibStub("AceAddon-3.0")[B]:NewAddon("MyAddon")[/B]
local L = LibStub("AceLocale-3.0"):NewLocale("MyAddon", "enUS", true)
local MyAddon = MyAddon
-- rest of code
With out the bolded section, all your doing is pulling a local reference of AceAddon, rather useless by itself :)
local MyAddon = {}
LibStub("AceAddon-3.0")[B]:NewAddon("MyAddon", MyAddon)[/B]
local L = LibStub("AceLocale-3.0"):NewLocale("MyAddon", "enUS", true)
-- rest of code
again different because this starts with a local table and embeds AceAddon Ontop of it. Just a different Implementation.
However i think you where getting at this idea:
local L = LibStub("AceLocale-3.0"):GetLocale("MyAddon_Locale")
MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
local addon = MyAddon
-- rest of code
Where one pulls a local reference to your locale table. It also creates the 1 global object for your addon and then sets a local reference to that for fast access.
General Practices would infer that there are really only 2 Global variables you should ever use. One for your base / core Addon Object (it's really optional), and One for your SavedVariables (requred to be global inorder for the client to save it)
local MyAddon = MyAddon
MyAddon = LibStub("AceAddon-3.0")
In the first line, MyAddon does not yet exist in any form, so the right-hand side evaluates to nil. (It's not an error; undefined globals silently resolve to nil by default, for good reasons too verbose for this post.)
So the first line is the same as "local MyAddon = nil", but because all variables start as nil, it's also the same as just "local MyAddon":
local MyAddon
MyAddon = LibStub(.......) -- name is local at this point
which is of course just the same as
local MyAddon = LibStub(.......)
There is no global MyAddon defined by your code here, but LibStub still does its own definitions.
OK, yes, I know I left off the end of the AceAddon call, but what I was getting at was is one of my examples better than the other? Having the
local MyAddon = MyAddon
before or after the rest, or does it matter? I don't think it would matter, unless what Farmbuyer said that it would me "nil" ... Of course, I could try it and find out :p
dafire, the bottom section wrt to the string and table functions, this makes sense if you use them alot. Like an LDB Display would use format like a cheep whore. But the ones at the top, all those frame methods are nil btw.. i don't think blizzard puts the frame method functions into the global scope.
OK, yes, I know I left off the end of the AceAddon call, but what I was getting at was is one of my examples better than the other? Having the
local MyAddon = MyAddon
before or after the rest, or does it matter? I don't think it would matter, unless what Farmbuyer said that it would me "nil" ... Of course, I could try it and find out :p
The order matters.
This:
local MyAddon = MyAddon
MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
reads like:
local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
And this:
MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
local MyAddon = MyAddon
reads like:
_G.MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
local MyAddon = _G.MyAddon
In the first case you only define a local variable.
In the second case you define a global variable, then create a local variable to which you assign the global variable value.
You have to declare local variables (with "local" statement) *before* using them.
does making functions local has no overhead at all ?
...
I wonder if this really make sense for functions that are not called often :9
It doesn't make them have no overhead - it merely removes the cost of a table lookup every use. As for doing this with functions which aren't called often, I see no point. I generally use "luac -l" and look where it is telling me globals are being looked up, then decide if there would be a benefit from making a local definition instead. As Orionshock said, many if not all of those you listed in the upper section wouldn't benefit from being declared as locals - unless they're being used many times in a loop and aren't actually 'nil'.
does making functions local has no overhead at all ?
I found something like that in an addon:
<SNIP>
I wonder if this really make sense for functions that are not called often :9
The overhead is 8 bytes of memory in the heap per local function reference (the local variables are initially on the stack when you execute the main chunk, but they get move to the heap when the chunk execution completes and they go out of scope and Lua checks to see that existing closures still refer to them). And you also use an additional 4 bytes of memory for each function closure that uses them as upvalues.
Benefits is you avoid the _G table lookup per call.
OK, yes, I know I left off the end of the AceAddon call, but what I was getting at was is one of my examples better than the other? Having the
local MyAddon = MyAddon
before or after the rest, or does it matter? I don't think it would matter, unless what Farmbuyer said that it would me "nil" ... Of course, I could try it and find out :p
Neither example is really better or worse than the other because they both achieve the same end result and both cases access the _G table twice (not counting the LibStub access).
Here, the first line writes to _G.MyAddon on line 1, then reads it back in line 2. So 2 accesses.
MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
local MyAddon = MyAddon
Here, the code accesses _G twice, both on line 2. Once to read the value of _G._G, and then again to write to _G.MyAddon.
local MyAddon = LibStub("AceAddon-3.0"):NewAddon("MyAddon")
_G.MyAddon = MyAddon
The first is of a magnitude faster than the second. Hash table lookups ARE SLOW and are NOT CONSTANT TIME. The larger the table, the more time it takes to find it.
Could you please elaborate? People normally use hashtables for their constant lookup times, and we typically think of them as being more effective as the data set grows larger (compared to a sequential data structure). This seems counter-intuitive to me, but perhaps Lua does things differently.
Could you please elaborate? People normally use hashtables for their constant lookup times, and we typically think of them as being more effective as the data set grows larger (compared to a sequential data structure). This seems counter-intuitive to me, but perhaps Lua does things differently.
Although lua table lookup is using a hastable, it doesn't mean that keys can't have the same hash value, and thus a sequential scan in the list of keys having the same hash value is needed. The probability of this occuring grows with the number of elements in the table.
Note finally that a GETGLOBAL opcode is slightly slower than a GETTABLE opcode, as the opcode must determine the function environment before doing the equivalent of a GETTABLE on it.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
vs
you may overwrite another global with the same name
If you do need persistence beyond scope place your variable in a subtable of your addon.
That way you do avoid naming collisions unless another addon tries to use the same global table/name.
You don't need the do ... end - see Elsia's example above.
Locals are stored on the function call stack and are released when the function returns to the caller.
Globals are stored in a _G[] global table which is stored on the heap.
Accessing a local "myVar" is just reading it from memory off the stack.
Accessing a global "myVar" tells Lua to perform a table lookup on _G to find the value of _G["myVar"].
A function or file scope chunk can have up to 200 locals defined.
The first is of a magnitude faster than the second. Hash table lookups ARE SLOW and are NOT CONSTANT TIME. The larger the table, the more time it takes to find it.
All Lua code from all addons share the same global namespace _G. So if your addon used the global variable "myVar" and another addon also happen to use that exact same global variable "myVar", those 2 addons would likely kill each other.
At the top of many addons, you would see code like
local pairs = pairs
The reason is simply to create a local variable called "pairs" that points to the same function as the global _G["pairs"].
or
I would think it doesn't matter because when you get to
it has already been made local either way.
With out the bolded section, all your doing is pulling a local reference of AceAddon, rather useless by itself :)
again different because this starts with a local table and embeds AceAddon Ontop of it. Just a different Implementation.
However i think you where getting at this idea:
Where one pulls a local reference to your locale table. It also creates the 1 global object for your addon and then sets a local reference to that for fast access.
General Practices would infer that there are really only 2 Global variables you should ever use. One for your base / core Addon Object (it's really optional), and One for your SavedVariables (requred to be global inorder for the client to save it)
In the first line, MyAddon does not yet exist in any form, so the right-hand side evaluates to nil. (It's not an error; undefined globals silently resolve to nil by default, for good reasons too verbose for this post.)
So the first line is the same as "local MyAddon = nil", but because all variables start as nil, it's also the same as just "local MyAddon":
which is of course just the same as
There is no global MyAddon defined by your code here, but LibStub still does its own definitions.
before or after the rest, or does it matter? I don't think it would matter, unless what Farmbuyer said that it would me "nil" ... Of course, I could try it and find out :p
I found something like that in an addon:
I wonder if this really make sense for functions that are not called often :9
The order matters.
This:
reads like:
And this:
reads like:
In the first case you only define a local variable.
In the second case you define a global variable, then create a local variable to which you assign the global variable value.
You have to declare local variables (with "local" statement) *before* using them.
It doesn't make them have no overhead - it merely removes the cost of a table lookup every use. As for doing this with functions which aren't called often, I see no point. I generally use "luac -l" and look where it is telling me globals are being looked up, then decide if there would be a benefit from making a local definition instead. As Orionshock said, many if not all of those you listed in the upper section wouldn't benefit from being declared as locals - unless they're being used many times in a loop and aren't actually 'nil'.
The overhead is 8 bytes of memory in the heap per local function reference (the local variables are initially on the stack when you execute the main chunk, but they get move to the heap when the chunk execution completes and they go out of scope and Lua checks to see that existing closures still refer to them). And you also use an additional 4 bytes of memory for each function closure that uses them as upvalues.
Benefits is you avoid the _G table lookup per call.
Neither example is really better or worse than the other because they both achieve the same end result and both cases access the _G table twice (not counting the LibStub access).
Here, the first line writes to _G.MyAddon on line 1, then reads it back in line 2. So 2 accesses.
Here, the code accesses _G twice, both on line 2. Once to read the value of _G._G, and then again to write to _G.MyAddon.
You might take a look at: http://www.lua.org/gems/sample.pdf There's an explanation on page 17.
Could you please elaborate? People normally use hashtables for their constant lookup times, and we typically think of them as being more effective as the data set grows larger (compared to a sequential data structure). This seems counter-intuitive to me, but perhaps Lua does things differently.
Although lua table lookup is using a hastable, it doesn't mean that keys can't have the same hash value, and thus a sequential scan in the list of keys having the same hash value is needed. The probability of this occuring grows with the number of elements in the table.
Note finally that a GETGLOBAL opcode is slightly slower than a GETTABLE opcode, as the opcode must determine the function environment before doing the equivalent of a GETTABLE on it.