I have a module script that contains all of the functions for my gui event handler local script. This module script is now erroring because the variable limit has been surpassed. I was rather surprised when this happened, but, because it did, I needed to find a way around it. All the variable definitions are wanted and used. This is a module script that has references to most of the guis in the game, along with references to remotes, objects, and various other things, so simply using fewer variables is not going to cut it.
As always, I did some discussion and research before posting this question. There were two main solutions that people came up with. Those are what I wish to ask about. Which one is best in performance, code convention, and general code simplicity?
Option One:
Use a do end
block / don't define variables locally. Now, both options are not ideal, but if they're the best, I'll definitely take them, because they're not that difficult to implement. For example, instead of defining player locally, I could do this:
player = players.LocalPlayer
or this:
do player = players.LocalPlayer end
Now, I don't see a significant difference between the two (other than the second seeming worse and useless), but I'll leave it up here because it was a suggestion someone made.
Option Two:
Use a table. Now, this option makes sense, but it does mean rewriting large portions of my code, which I'd like to avoid. Not only that, but how exactly should I implement tables? Should I have a different table for each chunk of variables that deal with similar things? Should I do that, but also put each different table into one main table? Should I just put everything into one main table? Should I leave some variable definitions, but move others into tables?
I'd appreciate advice on this matter. If you have a different solution altogether, feel free to post that as well. I'm open to pretty much anything that makes sense, works, and isn't going to require a massive overhaul of the whole system (which seemed pretty smooth until I ran into this limit).
Thanks!
(Note that using non-local variables in a do end
block doesn't help anything. Also, in terms of performance, local variables are slightly faster than non-local variables, and not using a table is slightly faster than using one - but the difference is very small; it's best to consider performance when working on a piece of code that (for instance) runs in a loop every frame.)
For the sake of organization, it is better to separate your script into smaller segments (ideally smaller scripts) that are each responsible for a smaller job (see https://en.wikipedia.org/wiki/Separation_of_concerns). If you can make each segment "know" as little as possible about other segments (and ideally knows about as few segments as possible), you decrease the number of dependencies for each segment. That way, if you later decide to change something, you minimize the amount of other code that you'll need to update.
To fix your problem, you could put all your variables into tables, but on its own this doesn't improve organization/separation of concerns and is also incurs a performance penalty (and a fair bit of rewriting).
Ways to help fix your problem that also help with organization:
do end
and local variables. The idea is to make sure that a variable is only in scope for a section of the script - define any functions that need to use it, then end the block. The goal is to have each section of a script only deal with one main idea. If you are successful, you may find that you can move some of the blocks into different scripts entirely (although this may not be easy to do if there are a lot of variables that are accessible to the entire original that the block relies on).Method 1, managing locals with scopes, is probably the least work and it should solve your immediate problem, though you should consider transitioning into the 2nd option over time, even if you don't want to do it all at once.
An example of method 1:
local Players = game.Players -- variable accessible to all blocks local someGlobalVar = thatManyBlocksUse do -- Manage a specific aspect of the GUI, ex some buttons local button1 = pathToButton1 local someLabel = etc -- use button1/someLabel/etc end do -- Manage a different aspect of the GUI -- more local variables -- etc end -- You can also "export" functionality from a scope by defining the variable outside the 'do end': local CountSpeciallyNamedChildren -- arbitrary piece of functionality do local specialNames = {SpecialName=true, VerySpecialName=true} function CountSpeciallyNamedChildren(obj) local ch = obj:GetChildren() local count = 0 for i = 1, #ch do if specialNames[ch[i].Name] then count = count + 1 end end return count end end -- You can now access CountSpeciallyNamedChildren but specialNames is hidden and therefore doesn't count towards the variable limit. It's also clear to see where "specialNames" is used/modified, making it easier to find bugs.