Local variables in a required module

Posted by Seriley on Tue 07 Sep 2010 02:06 AM — 6 posts, 27,161 views.

#0
If a local variable is declared in a module, outside of any block, and a script requires this module, then
1) The scope of the local variable in the module is the entire module
2) The scope of this variable does not expand to include a script that requires this module

Is this assumption correct?

The language is lua
Amended on Tue 07 Sep 2010 02:07 AM by Seriley
USA #1
Yes, that's right. When a Lua script is loaded, it's as though you did loadstring("file contents") and called the result. As loadstring() return a function, locals defined within the file "chunk" remain completely local to that chunk.

Likewise, because the function is constructed by loadstring() and not defined inline, locals you define before loading the file are not visible to the loaded chunk.
Netherlands #2
I am kinda sleepy, so disclaimers apply to the following statements.

Yes, that is correct. You can of course easily check this stuff for yourself.

A good way to think of require (and in extension module(...)s too, altho some more magic happens there), is as a fancy dofile() that craps out big time when the file is missing or has errors. Now, dofile() is basically compiling the script into a block in its own context (a 'block', or anonymous function of sorts if you prefer), which is then executed.

Thus, long story short... think of any file you require as a function you call. While fancy stuff with regards to globals do happen, local variables live only in said execution of said function, making it impossible for outside sources to tamper with that particular local variable.

(If I was awake enough, I'd probably delete all the above and rewrite it, but make of it what you want to, and Lua fanatics, feel free to correct me where I am incorrect.)
Australia Forum Administrator #3
Seriley said:

1) The scope of the local variable in the module is the entire module


Not quite. The scope of the local variable is from the definition downwards.

For example:


print (a)  --> nil
local a = 42 


That may seem pedantic, but the scope is not the entire module.

Also consider this:


do
  local x = 99
  print (x)  --> 99
end

print (x)  --> nil


The local variable's scope is actually just downwards from its declaration in the enclosing block, in this case the do ... end block.

Remove the word "local" in that example and both times 99 is printed.

And this:


function f ()
  print (z)
end -- f

local z = 22

f ()  --> nil


In this example I have set up z (assigned the value 22 to it) before trying to use it in function f. However f does not recognise z as it was declared after it (f) was. So it prints nil.

Again, removing local would let z print as 22.
Amended on Tue 07 Sep 2010 03:19 AM by Nick Gammon
Australia Forum Administrator #4
Seriley said:

2) The scope of this variable does not expand to include a script that requires this module


That bit is right. The idea of using "local" in modules is to isolate their effect from the rest of your scripts.

Another thing to look at is the module function. This sets up a special environment for your module so that even non-global variables are protected from being accessed in global namespace of the script that requires it. Except, as a sub-variable of the module itself.

Also it protects the caller global namespace from access unless you take extra steps. So if there is a global variable "foo" in your calling script, the module cannot affect it.

So basically using the module function protects you from the module corrupting the main program, and vice-versa.

As an example, look at copytable.lua that comes with MUSHclient.

Now if you load that, and try to access the non-local function "deep" you cannot do so directly:


require "copytable"
print (deep)  --> nil


However you can get it as a sub-item of copytable itself, eg.


require "copytable"
print (copytable.deep)  --> function: 018942E8

#5
Thanks to all for your responses. I had done a quick and dirty test before posting my original question, but sometimes my tests miss edge cases (as was pointed out here).

This forum is a great place to learn!