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?
These variables are referred to as local because they exist (and are visible) only during the lifetime of the method. They are said to have local scope. When the method ends, the variable goes out of scope and is destroyed. C# divides the world of types into value types and reference types.
Local Variable: These variables are declared within a method but do not get any default value. They are usually created when we enter a method or constructor and are destroyed after exiting the block or when the call returns from the method.
Closures can avoid the use of global values and provides some form of data hiding. It can also provide an object oriented solution to the problem.
In Python or any other programming languages, the definition of local variables remains the same, which is “A variable declared inside the function is called local function”. We can access a local variable inside but not outside the function.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With