Thread Tools Display Modes
02-09-20, 05:41 PM   #1
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
More than 200 local variables

Hi all

My addon stops working once I have more than 200 local variables, the error gives me the following message.
Code:
4x AAA\AAA 8.4.8.3.lua:5589: main function has more than 200 local variables
I understand that I can reduce the number of variables to keep under that 200 cap but I would like to know why such a cap exists?


Also I can define variables using
Code:
local a, b, c, d, e = 1, 2, 3, 4, 5
However this still counts as 5 local variables, is there a way to define local variables in a way that dose not increase the overall count of local variables?
  Reply With Quote
02-09-20, 08:30 PM   #2
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
Define a local table at the top of your addon and use keys instead of separate variables.

For example:

Lua Code:
  1. -- instead of this
  2. local a, b, c, d, e = 1, 2, 3, 4, 5
  3.  
  4. -- use this
  5. local vars = {}
  6. vars.a, vars.b, vars.c, vars.d, vars.e = 1, 2, 3, 4, 5

You can even use the provided addon table in the second vararg return that's handed to each of your addon's files.

Lua Code:
  1. local addonName, addonTable = ... -- the very first line of your addon file

This addon table is shared across all your Lua files under a single .toc file.

I honestly wasn't aware of a local variable cap, but I've had tables with thousands of entries in them.

Last edited by Kanegasi : 02-09-20 at 08:35 PM.
  Reply With Quote
02-09-20, 08:49 PM   #3
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
It's a limit in Lua itself, and has to do with how much room it has for local variables in one scope, iirc.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
02-09-20, 09:27 PM   #4
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
Hi Kanegasi & Seerah

Thanks for the feedback and advice, both really appreciated.
  Reply With Quote
02-11-20, 10:34 AM   #5
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,308
Originally Posted by Kanegasi View Post
Define a local table at the top of your addon and use keys instead of separate variables.

For example:

Lua Code:
  1. -- instead of this
  2. local a, b, c, d, e = 1, 2, 3, 4, 5
  3.  
  4. -- use this
  5. local vars = {}
  6. vars.a, vars.b, vars.c, vars.d, vars.e = 1, 2, 3, 4, 5
The entire appeal of using local variables aside from limiting scope is you save an index lookup in the global table. Putting variables in a local table completely negates this since you're re-adding the index operation you were trying to save.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
02-11-20, 11:38 AM   #6
jeruku
A Cobalt Mageweaver
 
jeruku's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 223
Originally Posted by SDPhantom View Post
The entire appeal of using local variables aside from limiting scope is you save an index lookup in the global table. Putting variables in a local table completely negates this since you're re-adding the index operation you were trying to save.
Yes, but in this case the number of local variables exceeds Lua's capacity for a single scope. I mean, if you're using 200+ local variables a table can be upvalued no differently and though table lookups aren't as fast as a local variable it's not using 200+ local variables.
__________________
"I have not failed, I simply found 10,000 ways that did not work." - Thomas Edison
  Reply With Quote
02-11-20, 03:41 PM   #7
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
At least it's a local table and not a global one.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
02-12-20, 08:12 AM   #8
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,308
There are still better options. Making sure you put local variables only in the scope they're being used (you can force a scope if you need using a do ... end block). Limiting what functions you make local references of. Etc.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
02-12-20, 04:23 PM   #9
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
I agree. It's possible that the code could be optimized.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
08-26-20, 07:52 PM   #10
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
Hi all

Sorry for the necro thread but I like to keep the same subjects together instead of creating multiple threads.

Some follow up questions.

I have hit the 200 limits again as I have implemented new features and functionality.

Should functions all be local as well or is it better to use complicated/unusual names to ensure there is no cross-pollination? is the same for frame names as well?

Is it better to have functions and frames to be in separate lua files?

Cheers
  Reply With Quote
08-27-20, 09:46 AM   #11
Zlodo
A Defias Bandit
AddOn Author - Click to view addons
Join Date: Nov 2010
Posts: 3
It's 200 local variable per function, correct? So if you exceeded it you probably have a gigantic, unwieldy function that can be split into simpler functions. Keep in mind that the top level of a Lua file is also a function.
  Reply With Quote
08-28-20, 07:24 PM   #12
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
Hi Zlodo

I don't have locals inside functions as each variable exists within its function.

It is each frame, button and function that are local; I have a few workarounds such as having frame and button names in a table, eg;
Lua Code:
  1. local framesNbuttons = {frameA, frameB, buttonA, buttonB}
  2.  
  3. framesNbuttons.frameA = CreateFrame("Frame")
  4.  
  5. framesNbuttons.buttonA = CreateFrame("Button")

I was just wondering if there is a better way to approach this issue.

Further, could I do the same thing with functions?
Lua Code:
  1. local functions = {functionA, functionB}
  2.  
  3. functions.functionsA = function runFunctionA ()

I have tried this with no success, yet I am not sure if this is a correct way of using functions in a table or not.
  Reply With Quote
08-28-20, 07:46 PM   #13
Kanegasi
A Molten Giant
 
Kanegasi's Avatar
AddOn Author - Click to view addons
Join Date: Apr 2007
Posts: 666
Lua Code:
  1. local functions = {}
  2. functions.functionA = function()
  3.     -- stuff here
  4. end
  Reply With Quote
08-28-20, 08:00 PM   #14
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Originally Posted by Walkerbo View Post
Lua Code:
  1. local framesNbuttons = {frameA, frameB, buttonA, buttonB}
  2.  
  3. framesNbuttons.frameA = CreateFrame("Frame")
  4.  
  5. framesNbuttons.buttonA = CreateFrame("Button")
That doesn't do exactly what you think it does. Your code is creating a table that looks like this:
Lua Code:
  1. local framesNbuttons = {
  2.      [1] = frameA,
  3.      [2] = frameB,
  4.      [3] = buttonA,
  5.      [4] = buttonB,
  6.      ["frameA"] = <yourframe>,
  7.      ["buttonA"] = <yourbutton>,
  8. }
Of course, since frameA, frameB, ... are nil at the time of declaring your table, they aren't actually stored in it and those four numerical keys are tossed at the next garbage collection. So... pointless, really.

Just do:
Lua Code:
  1. local framesNbuttons = {}
  2. framesNbuttons.frameA = CreateFrame("Frame")
  3. framesNbuttons.buttonA = CreateFrame("Button")
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
08-28-20, 08:28 PM   #15
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,857
Or create single frames with their component parts as keys on the frame.

Lua Code:
  1. local frameA = CreateFrame("Frame", nil, UIParent)
  2. frameA.Button1 = CreateFrame("Button", nil, frameA)
  3. frameA.Texture1 = frameA:CreateTexture()
  4. frameA.SubFrame1 = CreateFrame("Frame", nil, frameA))
  5. frameA.SubFrame1.Button1 = CreateFrame("Button", nil, frameA.SubFrame1)
1 local used.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
08-29-20, 08:48 AM   #16
MunkDev
A Scalebane Royal Guard
 
MunkDev's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2015
Posts: 431
I think your code is severely flawed if you have 200 local variables in a single scope. You should read tutorials on how Lua works, especially I think you'll find tables interesting, and some tutorials on programming in general.
__________________
  Reply With Quote
09-01-20, 09:53 PM   #17
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
Hi all

@MunkDev; I can almost guarantee that my code is flawed and likely very inefficient; I am self-taught with no background in coding at all.

@Seerah; thanks for detailing how the table laid out, this was extremely helpful as it really showed how I was using some tables wrong.

@Fizzlemizz; thanks for the example code, this put Seerah's explanation into action and has been a massive help in the way I approach tables and frames.

Just a follow-up question;

Is this chunk;
Lua Code:
  1. local frameA = CreateFrame("Frame", frameA, UIParent)
  2. frameA.Button1 = CreateFrame("Button", frameAButton1, frameA)
  3. frameA.Button1:ClearAllPoints()
  4. frameA.Button1:SetPoint("CENTER", 0, 0)
  5. frameA.Button1:SetSize(40, 40)
the same as;
Lua Code:
  1. local frameA = CreateFrame("Frame", frameA, UIParent)
  2. frameAButton1 = CreateFrame("Button", frameAButton1, frameA)
  3. frameAButton1:ClearAllPoints()
  4. frameAButton1:SetPoint("CENTER", 0, 0)
  5. frameAButton1:SetSize(40, 40)

In the first chunk, I add the button and the button properties directly to the frame.

In the second I add the button to the frame and then add the properties to the button itself.

Both chunks seem to work but I do not know which one is the proper/correct way of coding this.
  Reply With Quote
09-01-20, 11:34 PM   #18
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,857
Lua Code:
  1. local frameA = CreateFrame("Frame", "frameA", UIParent)
  2. frameAButton1 = CreateFrame("Button", "frameAButton1", frameA)
  3. frameAButton1:ClearAllPoints()
  4. frameAButton1:SetPoint("CENTER", 0, 0)
  5. frameAButton1:SetSize(40, 40)

frameA is a local
frameAButton1 is a global

I added quotes around the frame names as without them, it would just be the same as using nil unless as variables they had been initialised earlier.

As someone once told me, frames are just special types of tables.

Lua Code:
  1. local frameA = CreateFrame("Frame", "frameA", UIParent)
  2. frameA["Button1"] = CreateFrame("Button", "frameAButton1", frameA)
  3. frameA["Button1"]:ClearAllPoints()
  4. frameA["Button1"]:SetPoint("CENTER", 0, 0)
  5. frameA["Button1"]:SetSize(40, 40)
is the same as the original.

Even:
Lua Code:
  1. local f = CreateFrame("Frame", "frameA", UIParent)
  2. f = CreateFrame("Button", "$parentButton1", f)
  3. f:ClearAllPoints()
  4. f:SetPoint("CENTER", 0, 0)
  5. f:SetSize(40, 40)
Would reduce the number of locals used as you are just re-using the one local. Although doing this you lose the local reference to the top level frame but you could still reference it using the frames name ("frameA") as these are added to the global table (note the use of $parent in the button name)

Lua Code:
  1. frameA:SetSize(100, 100)
  2. frameAButton1:SetText("New Button Label")
This is very much the old XML way of doing things before XML frames had the parentKey attribute.

This being the case,
Code:
local frameA = CreateFrame("Frame", "frameA", UIParent)
local frameA would be fine as a local.

"frameA" would be rubbish as a frame name. Being created as a global there's too much chance of a clash (I forget how it woks but I'm pretty sure first frame with a name is added to the global table, any others with the same name are ignored).
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.

Last edited by Fizzlemizz : 09-02-20 at 12:24 AM.
  Reply With Quote
09-02-20, 09:49 PM   #19
Walkerbo
A Cobalt Mageweaver
 
Walkerbo's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 233
Post

Hi all

@Fizzlemizz Thanks for your more detailed explanation, the simple statement of "As someone once told me, frames are just special types of tables." makes things crystal clear for me.

Thanks to all for your help.

Cheers
__________________
"As someone once told me, frames are just special types of tables, and tables are special types of pointers."
Fizzlemizz
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » More than 200 local variables

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off