Should I explicitly declare a variable in the outermost scope of a Lua 4 script a
local variable versus a global variable? Should I avoid one or the other? Thanks.
For instance:
local foo = 5
versus
faa = 8
I believe you already know that local variables are variables where they exist only within a certain scope, while normal variables are global and are included within the _G table. However, according to Lua's Performance Guide, it also helps to make your code faster:
Lua precompiler is able to store all local variables in registers. The result is that access to local variables is very fast in Lua. For instance, if a and b are local variables, a Lua statement like a = a + b generates one single instruction.
So, it is easy to justify one of the most important rules to improve the performance of Lua programs: use locals!
Related
I've seen in several places that people put at the top of their init.lua: local vim = vim. What is the purpose of this? I could understand aliasings like local v = vim or local g = vim.g but it appears like local vim = vim doesn't do anything.
local name = name is called a localization. There are multiple good reasons to localize variables:
Performance
Recall that for environmental (usually global) variables, name is just syntactic sugar for _ENV.name which in turn is syntactic sugar for _ENV["name"]; acessing a local variable on the other hand is practically a single array access where Lua knows the array index at compile-time (it's either an upvalue or a local, which get stored in different arrays; upvalues of functions are slightly slower).
The array/"register" access will be faster than accessing the hash part of _ENV and searching for "name" (hash map lookup is slower than array access). Technically Lua even has to first check the (implicit) _ENV upvalue (called "function environment" in Lua 5.1 / LuaJIT) to see which table to index.
In conclusion, local variables / upvalues are usually faster than environmental variables; JIT-compilers like LuaJIT might optimize this out, but even LuaJIT has to consider the possibility that _G.vim may be modified, which brings us to our second point:
Semantics
it appears like local vim = vim doesn't do anything
For the most part this is correct, but not quite: local vim = vim means "get the vim environmental (global) variable at the time this line of code is executed (the load time of the script if it's at the top), then store it in a 'private' variable"; without this line, later modifications of the environment (e.g. vim = nil) outside of the script will have an effect because the environment is reindexed. With this line, you get to keep your reference to the vim table no matter what happens later on, which also provides an assurance to Lua / presumably also LuaJIT that it won't change later on.
Additionally, if a metatable is set on _G, _G.name can return different results at different times based on the metamethod that returns it. Again localizing ensures that your local variable doesn't change (unless you explicitly change it).
Code Quality
Localizing all used environmentals makes your dependencies explicit, akin to the "import" statements of other languages. In Lua, require is not consistently used; some libraries are simply part of the global environment _G, such as vim in your example, whereas others have to be required. For require, you'd use local lib = require("lib"), then why not consistently do this for global variables as well, rather than redoing the indexing operation every time?
Environment Changing
This will probably rarely be the reason, but it's worth noting.
If you set a custom environment for your chunk, you will have to find a way to keep accessing global variables.
There are two options for this:
One is to use a metatable with __index = _G (or whatever the parent environment is to be), but this is inefficient and unpredictable; it practically means your environment inherits everything from its parent environment, so e.g. _ENV.math.floor would be _G.math.floor, which may be considered dirty if you want to export your _ENV as API table of a module.
The other is to localize all global variables you use. This doesn't have the drawbacks of the first solution; it is more performant, more predictable, and doesn't force you to have your environment inherit from the parent environment.
In a Roblox game I'm programming, I want to have a table of boolean values to iterate over ensuring that they're all false before making another one true, e.g.;
local bool1 = true
local bool2 = false
local bool3 = false
local bool4 = false
local tbl1 = {}
table.insert(tbl1,boolX) -- where "X" is the number above, did this in interest of shortening
for i,v in pairs(tbl1) do
if v then v = not v end
end
However, as stated in the penultimate paragraph of section 2.1 of the 5.3 manual (knowing, albeit, that Luau uses 5.1 as its base);
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
That in mind, that means that I'm not actually shoving bool1 through bool4 into the table, just their values; the table would look like {true, false, false, false}. This means that I can't simply write a loop to iterate through the table and invert any trues I find;
local bool1 = true
local tbl1 = {}
table.insert(tbl1,bool1)
tbl1[1] = false
print(bool1)
print(tbl[1])
--output:
-- true
-- false
I should point out that I very well could just shove all my variables into one giant if/else and call it a night, but that is a lot of variables to check, a lot of typing, and I can't think of any other more elgant and less tedious way other than finding a form of iteration over them all.
I want to be able to have an actual reference, in some form, to the actual variables so that I can modify them from within the table and make them iterable.
I've attempted to follow the examples given in the best answer to this question, with no successes. I would need to be able to, and cannot with these examples, substitute for any given variable at any given time, rather than just having one or two I want declated and thus returned as shown. I've attempted wrapping them in a function to provide my table and variable as arguments, but that doesn't seem to have any effect; it either outputs nothing, or nil.
The following answer after has one example that seems like it could work, but overall is pointless for what I'm trying to achieve; I don't want to re-declare or re-assign the variables I already have, I just want to return the specific value.
I've attempted using a key/value pair, making the key the potential variable name and making it equal the variable's value, but I've no way to make that key return a variable of the same name. I even attempted merging this method and the setmetatable method mentioned in the first set of examples to see if I couldn't substitute from there, to no avail.
I should point out that, while I'm not a complete newbie to Lua or Luau, I'm also not an expert in the field by any meaning of the word; I'll catch on quick, but where possible, explain like I'm 10.
The only way to iterate over local variables that are not referenced by table fields, is to use debug.getlocal in a loop.
Opinionated:
But this is a very bad approach to your problem.
You should refactor the code. If you need to update a list of variables have them in a list from the start. Don't be afraid of refactoring. Improving things usually pays off on the long term.
If your codebase is so bad that you are afraid of putting a few variables into a table you should really think over the design.
There is no way to do this in Roblox Luau.
Any potential way to do so in standard Lua is impossible to do in Luau due to how heavily sandboxed the latter is compared to the former.
Possible solutions that were recommended via comments include: making the variables needed available in _G as globals, then using them there; or using a pointer value in the table equivalent to the one you want, even though it won't technically change the value you want itself.
Another answer recommends the use of debug.getlocal() for standard Lua, but doesn't work in Luau; keep this in mind when attempting to use it, as you will get an attempt to call a nil value error.
The recommended way to do this is not to do it at all, and instead have your variables and/or values in your table from the start.
Not only does this provide ease-of-access in many cases, but it will allow you to iterate through them significantly easier than trying to shove them into tables and the like. Refactoring, if you need to do something similar to this, is highly recommended across the board.
My apologies if the title to this question is a bit confusing. I could not find a better way to describe my question. I have always bashed my head against to wall to figure out this specific situation in lua.
Given the example below, will lua look for the function inside the localized variable on the stack or look for it in the hash part of the table? Take note that the global function is written as SomeGlobalFunc() instead of _G.SomeGlobalFunc()
--localize the global environment
local _G = _G
--run global func
SomeGlobalFunc()
The Lua manual says:
_G is never used internally, so changing its value will affect only your own code
This means all operations with _G do not affect Lua program behavior, except when you use this variable explicitly, such as _G.func()
In other words, Lua knowns where the globals table is located without accessing variable _G
P.S.
Lua uses internally _ENV variable, not _G
(Some background: I am not experienced with lldb or python and don't work on them frequently, but currently need to make some basic scripts for debugging an iphone program)
I am currently stopped at a breakpoint in side a function, and want to check the value of an array that has been accessed inside this function
This array is declared as
Float32 my_array[128];
and has global scope. I can view the array using print command, but I would like to make a python script so that I have more control over the output formatting and possibly plot the array elements as a graph using matplolib later on.
I am looking at the sample python code given in this question, and using the python given there I have verified that I can view local variables in this function (where currently I am stopped at a break point). For example, if I change 'base' in base=frame.FindVariable('base') to my local variable 'k' (the local variable is not an array) ,
base=frame.FindVariable('k')
then print base I can see the value of k. However, if I try this,
base=frame.FindVariable('my_array')
and do print base it gives me No value. How can I write a python command to get the values of any kind of variable currently in scope? Preferably it works for normal variables (int, float), arrays, and pointers, but if not, finding values of arrays are more important at the moment.
SBFrame.FindVariable searches among the variables local to that frame. It doesn't search among the global variables.
For that you need to use a search with a wider scope. If you know that the global variable is in the binary image containing the your frame's code - lldb calls that binary image a Module - then you can find the module containing that frame and use SBModule.FindGlobalVariables. If that's not true, you can search the whole target using SBTarget.FindGlobalVariables. If you know that only one global variable of that name exists, you can use FindFirstGlobalVariable variant.
All these commands will find variables of any type, and they all consistently return SBValues so you can format them in a consistent manner regardless of how you find them. For statically allocated arrays, the array elements are its children, so you can fetch individual elements with SBValue.GetChildAtIndex.
You can get to a SBFrame's module like:
module = frame.module
and its target:
target = frame.thread.process.target
lldb separates the contexts in which to search for variables primarily for efficiency. If SBFrame.FindVariable searched for globals as well as locals, a mistyped variable name would be a much more expensive mistake. But it also makes the call more predictable since you will never get some random global from some shared library that the system loaded on your behalf.
I'm needing to reset some variables in a loop in order to assign the new values (like finding the index of a substring) i cannot reuse the same var so i must unset it and as far as i know the f(var) only works in a shell?
so is there no way to do this in a script?
f() is a shell-only command.
Erlang as a language uses immutable variables, and as such does not allow the resetting of variables within the code itself. The recommendation is to get comfortable with recursion, list comprehensions, mapping, or folding in order to accomplish "loops" which don't exist in the procedural sense in Erlang.
If you must rely on variable state, the closest thing you get to mutable variables is the process dictionary: get/1 and put/2. These are generally discouraged unless there is a good reason for using them.