How does local variables actuallly work in lua? - lua

I know this is very basic question but i'm pretty much confused by the local variables & their scope in lua, for instance if i write local x=12, it means that the variable x is a local variable & it's value is 12, but instead if i write local x & in the next line x=12, does this mean the same as in previous case or x=12 is treated as a global variable?

You can think of it as two totally independent things:
local x creates a "slot" in the local scope to hold a value, i.e. a variable. This variable is named x. From that point forward, until you exit that scope, any reference to x will refer to that local x.
x = 12 puts a value into the variable x. If you've previously created a local slot named x, that's where it'll go. If there is no local x in scope, it'll go into the global scope.
local x = 12 is just a shorthand for combining these two things, creating a local variable and assigning it a value at the same time.
So yes, your two scenarios are effectively equivalent.
local x
x = 12
And
local x = 12
Do the same thing.

You only use the local keyword once per scope, so that second access of x in your example will use the local x. If you then wish to access the global x, you can use __G.x

Related

Lua is it possible to load all local variables into a table, and/or dynamically create a local variable?

I have actually been wondering about this question for a long time, and I can recall reading something somewhere on the internet about loading all local variables into a table, but I could never find it again.
What I am wondering is if there is basically any way to dynamically create a local variable, similar to how you can dynamically create a global variable.
In Lua you can create dynamic global variables simply by saying:
local my_env = getfenv(1);
for i = 1, 10 do
my_env["OMG_DYNAMIC_GLOBAL_VARIABLE_"..i] = i * i;
end
But I have always wondered if there is a way to essentially do the same or a similar thing for local variables. Something like
for i = 1, 10 do
local["OMG_DYNAMIC_LOCAL_VARIABLE_"..i] = i * i;
end
would kind of be pseudo code for what I am trying to do.
As a second part to my question, I am wondering if there is any way to possibly iterate through every local variable in the current scope? I guess pseudo code for what I am trying to do would look something like:
local a = 123;
local b = 321;
LocalVars = {(local)}; --the table with the local variables in it.
for i,v in pairs(LocalVars) do print(i, v); end
I would appreciate any help regarding either part of my question.
Thanks
the table with the local variables in it
There is no table with local variables. Local variables do not exist in compiled Lua. There are simply locations on the Lua stack and/or upvalues. Even the names of local variables are lost during the compilation process.
Local variables are always static constructs of the Lua source code. They never exist within a table. If you need a non-static construct, use a table. That's what tables are for. That's (part of) why Lua globals are in a table.
I don't see the advantage of what you proposed over a regular local table except for syntactic sugar.
local locals = {}
locals.a = 123
locals.b = 321
for i,v in pairs(locals) do
print(i, v)
end
The syntax you proposed does not make the program clearer or easier to read in any way. In fact it even creates new problems. Does the following print c as well or does it not because it is in a nested local scope?
for i,v in pairs(LocalVars) do
local c = 1729
print(i, v)
end

local variable cannot be seen in a closure across the file?

Suppose I have the following two Lua files:
In a.lua:
local x = 5
f = dofile'b.lua'
f()
In b.lua:
local fun = function()
print(x)
end
return fun
Then if I run luajit a.lua in shell it prints nil since x cannot be seen in the function defined in b.lua. The expected printing should be 5. However if I put everything in a single file then it's exactly what I want:
In aa.lua:
local x = 5
local f = function()
print(x)
end
f()
Run luajit aa.lua it prints 5.
So why x cannot be seen in the first case?
As their name suggests, local variables are local to the chunk.
dofile() loads the chunk from another file. Since it's another chunk, it makes sense that the local variable x in the first chunk isn't seen by it.
I agree that it is somewhat unintuitive that this doesn't work.
You'd like to say, at any point in the code there is a clear set of variables that are 'visible' -- some may be local, some may be global, but there is some map that the interpreter can use to resolve names of either kind.
When you load a chunk using dofile, then it can see whatever global variables currently exist, but apparently it can't see any local variables. We know that 'dofile' is not like C/C++ inclusion macros, which would give exactly the behavior you describe for local variables, but still you might reasonably expect that this part of it would work the same.
Ultimately there's no answer but "that's just not how they specified the language". The only satisfying answer is probably along the lines 'because otherwise it would cause non-obvious problem X' or 'because then use-case Y would go slower'.
I think the best answer is that, if all names were dynamically rebound according to the scope in which they are loaded when you use loadfile / dofile, that would inhibit a lot of optimization and such when compiling chunks into bytecode. In the lua system, name resolution works like 'either it is local in this scope, and then it binds to that (known) object, or, it is a lookup in the (unique) global table.' This system is pretty simple, there are only a few options and not a lot of room for complexity.
I don't think that running byte code even keeps track of the names of local variables, it discards them after the chunk is compiled. They would have to undo that optimization if they wanted to allow dynamic name resolution at chunk loading time like you suggest.
If your question is not really why but how can I make it work anyways, then one way you can do it is, in the host script, put any local variables that you want to be visible in the environment of the script that is called. When you do this you need to split dofile into a few calls. It's slightly different in lua 5.1 vs lua 5.2.
In lua 5.1:
In a.lua:
local shared = { x = 5 }
temp = loadfile('b.lua')
setfenv(temp, shared)
f = temp()
f()
In lua 5.2:
In a.lua:
local shared = { x = 5 }
temp = loadfile('b.lua', 't', shared)
f = temp()
f()
The x variable defined in module a.lua cannot be seen from b.lua because it was declared as local. The scope of a local variable is its own module.
If you want x to be visible from b.lua, just need to declare it global. A variable is either local or global. To declare a variable as global, just simply do not declare it as local.
a.lua
x = 5
f = dofile'b.lua'
f()
b.lua
local fun = function()
print(x)
end
return fun
This will work.
Global variables live within the global namespace, which can be accessed at any given time via the _G table. When Lua cannot solve a variable, because it's not defined inside the module where is being used, Lua searches that variable in the global namespace. In conclusion, it's also possible to write b.lua as:
local fun = function()
print(_G["x"])
end
return fun

Explanation about “local foo = foo” idiom in Lua

In Programming in Lua (3rd Ed.) by Roberto Ierusalimschy it is stated that
A common idiom in Lua is
local foo = foo
This code creates a local
variable, foo, and initializes it with the value of the global
variable foo. (The local foo becomes visible only after its
declaration.) This idiom is useful when the chunk needs to preserve
the original value of foo even if later some other function changes
the value of the global foo; it also speeds up the access to foo.
Could someone explain this more in detail and provide a simple example?
At the moment, the only use I can think of for this idiom is to manage local variables (in a given block) that have the same names as global variables, so that the global variable is left unchanged after the block.
An example:
foo = 10
do
local foo = foo
foo = math.log10(foo)
print(foo)
end
print(foo)
this gives:
1
10
But the same could be accomplished without using the idiom at all:
bar = 10
do
local bar = math.log10(bar)
print(bar)
end
print(bar)
that gives the same result. So my explanation doesn't seem to hold.
I've seen this used more often as a optimization technique than as a way to preserve original values. With the standard Lua interpreter, every global variable access and module access requires a table lookup. Local variables, on the other hand, have statically-known locations at bytecode-compile time and can be placed in VM registers.
In more depth: Why are local variables accessed faster than global variables in lua?
The explanation is correct; I'm not sure why you are not satisfied with your example. To give you a real example:
local setfenv = setfenv
if not setfenv then -- Lua 5.2+
setfenv = function() ..... end
end
Another reason is to preserve the value as it is at this moment, so that other functions that use that value (in a file or a module) would have the same expectations about that value.
Wrapping a global:
do
local setmetatable = setmetatable
function _ENV.setmetatable(...)
-- Do your thing
return setmetatable(...)
end
end
Reducing overhead by using a local instead of doing a lookup in the globals-table (which is a local btw.):
local type = type
for k, v in next, bigtable do
if type(v) == "string" then
-- Do one thing
else
-- Do other thing
end
end
I think you're splitting hairs, unintentionally.
local bar = math.log10(bar)
is essentially the same as local bar = bar in spirit, but we it would be less useful to claim that the idiom is local bar = a(bar), because we may want to handle the local in some way other than passing it to a function first -- e.g. appending it to something.
This point is that we want to refer to the local bar, just as you say, not exactly how the conversion from global to local is done.

How to define a variable in Lua and how to call it in other Lua script in Cocos2d-x

How to define a variable(constant) in Lua and how to call it in other Lua script in Cocos2d-x?
In my way:
main.lua
local r = require("src/Square")
local constant= r:getConstant()
Square.lua
function Square:getConstant()
return 10
end
Are there any other more elegant way? Any suggestions will be appreciated.
You can make it a global variable:
constant = r:getConstant()
but the variable will not be constant. Lua does not know the concept of immutable/readonly/const variables.
There are tricks to use a Lua table's metatable to prevent the value from changing, though that requires the value to be in the table, and you can't prevent the table from being changed (ie set to nil or its metatable replaced).
Simply using a function that returns a constant value is the easier way to ensure const-ness of the value.
What I've also done in the past is to use a notation that marks constant values, for instance:
_constant = 10
local _localConstant = 11
The _ prefix denotes the variable as a constant. Alternatively an ALL-CAPS style analogue to #define macros works well if these are known constants in C/C++ or commonly known frameworks (ie DBL_EPSILON or M_PI_2). It is just a reminder for the programmer(s).
Lastly, there's the "const" table which is a global table defining some supposed-to-be constant values:
const = {thisIsTen = 10, thatIsEleven = 11}
Using the table makes it clear those are constants:
result = 100 * const.thisIsTen
If you're looking for a const(constant) value that's read-only and can not be changed, you'll need to make a function for it (Which you already have). You also have to know that lua gets returns of basic types (number, boolean, nil, string) by value not by reference (Only if you return them by creation).
Here's the replacement for your function:
square.lua
Square = {}
Square.__index = Square
local _const = 10
function Square:GetConst()
local const = _const
return const
end
-- Test function
function Square:MoveUp()
_const = _const + 2
end
return Square
main.lua
local sr = Require("src/Square")
print(sr:GetConst()) -- 10
local plus = sr:GetConst() + 4
print(sr:GetConst(), plus) -- 10 14
sr:MoveUp()
print(sr:GetConst()) -- 12
Also take a note that the Square can be changed into a local function(Recommended), so in that case there won't be any troubles with next times creation of object.

Lua - equivalent to extern

Is there any variable in lua equivalent to extern variables in C++ ??
I want to be able to define the variables in one script and read/use those values in another.
From Scope Tutorial on lua-users wiki,
Any variable not defined as local is in the global scope. Anything in the global scope is accessible by all inner scopes.
For your question; let's say I've files one.lua and two.lua
one.lua
local x = 3
y = 17
two.lua
dofile( "one.lua" )
print( x, y )
The output shall be
nil 17
If you're still unsure if some variable will be local or global; you can use _G table for them. Like this:
_G.y = 17 -- Same as y = 17 in one.lua
They are called global variables. Any variable that is used without being declared local is global.
In other words, this is the default already. You don't have to do anything special.

Resources