23 posts
Posted 31 January 2015 - 05:18 PM
I'm currently writing a program that needs to run functions from external files. This in itself is trivial, weren't it for the fact that these functions need read/write access to a number of global variables. I never thought access to global variables could be problematic, however, I have run into some fairly curious scoping rules. After extensive experimentation, I found that this was local to computercraft. Consider the following example:
var = false
print(var)
loadstring("var = true")()
print(var)
When run on my physical PC, this will return false; true. When run on a Cc computer, it will return false; false. The same thing applies to loadfile, loadstring was used for brevity.
Is this an intended/known part of Cc? I've been assuming Cc's Lua implementation to be fairly identical to the original, but I could be wrong. If I'm not, I suppose I've got a bug report to write.
1426 posts
Location
Does anyone put something serious here?
Posted 31 January 2015 - 05:49 PM
This is because
CC overrides the environment however doesn't set the same environment for
loadstring /
loadfile. To get around this you can do:
setfenv(loadstring("var = true"), getfenv())()
355 posts
Location
Germany
Posted 31 January 2015 - 05:50 PM
I'm pretty sure this doesn't have to do with computercraft itself, but the library used by computercraft to host lua scripts.
I would assume, that you are running the script with your so called "physical PC" being lua.exe compiled of the "original" C source code downloadable at lua.org
The java version of lua can therefor behave different from it, as it's not "original".
Yeah, it seems that running loadstring creates some sort of environment for the entire chunk. I would be interested in the output of loadstring("print(var)")()
23 posts
Posted 31 January 2015 - 05:57 PM
This is because
CC overrides the environment however doesn't set the same environment for
loadstring /
loadfile. To get around this you can do:
setfenv(loadstring("var = true"), getfenv())()
Interesting. Could you elaborate on how/why that works? I haven't seen those functions before.
Yeah, it seems that running loadstring creates some sort of environment for the entire chunk. I would be interested in the output of loadstring("print(var)")()
I checked that too before posting.
var = true
loadstring("print(var)")()
Will return nil.
var = true
loadstring("var = false")()
loadstring("print(var)")()
print(var)
Will return false; true.
var =nil
loadstring("var = true")()
print(var)
Will, interestingly enough, return true.
797 posts
Posted 31 January 2015 - 06:00 PM
Loadstring and loadfile (and dofile?) set (well, leave) the environment as _G, but your script isn't running in _G because it's running in an environment created by os.run() called from shell.run(). Therefore, the global environment of something loaded with loadstring() won't be the same as the global environment of your entire script.
As mentioned above, setting the environment of the script loaded using loadstring() to the current environment will change its global environment to the global environment of the current script rather than _G.
If you don't understand environments, the PIL has a section about them I'm sure.
1426 posts
Location
Does anyone put something serious here?
Posted 31 January 2015 - 06:09 PM
Interesting. Could you elaborate on how/why that works? I haven't seen those functions before.
The
Programming in Lua book gives a better example, but I will try to explain.
getfenvThis gets the current environment, when you call
print (or any global function) the function is looked up in the table that
getfenv returns.
setfenvThis sets the environment a function executes in.
The examples you gave in the above post:
Spoiler
I checked that too before posting.
var = true
loadstring("print(var)")()
Will return nil.
.
I'll try to illustrate environments as boxes:
+---------------------+
| Global environment |
| +---------------+ |
| | Current file | |
| | var = true | |
| +---------------+ |
| var doesn't exist |
+---------------------+
var = true
loadstring("var = false")()
loadstring("print(var)")()
print(var)
Will return false; true.
+---------------------+
| Global environment |
| +---------------+ |
| | Current file | |
| | var = true | |
| +---------------+ |
| var =false |
+---------------------+
var =nil
loadstring("var = true")()
print(var)
Will, interestingly enough, return true.
+-------------------------+
| Global environment |
| +--------------------+ |
| | var doesn't exist | |
| +--------------------+ |
| Var = true |
+-------------------------+
Var doesn't exist in the child environment as you have set it to nil. This is because setting something a table to nil clears it, so it just looks it up in the parent environment instead.
Edited on 31 January 2015 - 05:10 PM
23 posts
Posted 31 January 2015 - 06:27 PM
Alright, thanks.
Since os.run() allows you to set the environment, could I also circumvent the issue by starting my script using os.run(_G, path)? Or rather, I certainly can, (I just tried) but will it cause other issues? It wouldn't surprise me if a lot of Cc functionality is dependent on it's default environment.
797 posts
Posted 31 January 2015 - 07:15 PM
The shell API isn't in _G, so your program wouldn't have access to any of the shell.* functions or variables.
23 posts
Posted 31 January 2015 - 07:28 PM
Alright, I can live with that. Anything else I should be concerned about?