This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Loading strings for variable naming
Started by Doyle3694, 14 December 2012 - 06:44 AMPosted 14 December 2012 - 07:44 AM
Hello everyone! Out of clear curiosity, none of my programs needs this, I would like to know if there is any way to load a string as a variable name, let's say I make a function in which you pass a desired variable name and then it will make that variable and make it equal to "hello", no practical use there, but would there be any way to do that. I would suspect loadstring(), but that runs a string as a function if im not misstaken?
Posted 14 December 2012 - 07:55 AM
Indeed, loadstring returns a function. But you can use it like this:
Edit: I'm on the phone, so I can't test this.
local var = loadstring("return "..varname)()
I would go for a more robust method and use the environment table. Like this:
local var = getfenv()[varname]
Edit: I'm on the phone, so I can't test this.
Posted 14 December 2012 - 08:39 AM
Can I do
local loadstring(var) = "hello"
?Posted 14 December 2012 - 09:30 AM
No, it would still be:Can I do?local loadstring(var) = "hello"
local varname = "blah"
loadstring("return "..varname)() = "hello"
I'm not sure that you can assign return values though, but I think lua supports it.loadstring puts the text in the body of a new function and returns a reference to that function. So if you do this:
local func = loadstring("return os.version")
local ver = func() -- now ver holds a reference to the variable os.version
print(ver)
ver = 1 -- reassign a number to ver
It would be translated to:
local func = function() return os.version end
local ver = func() -- now ver holds a reference to the variable os.version
print(ver)
ver = 1 -- reassign a number to ver
So in short this could be written as:
loadstring("return os.version")() = "hello"
You could also use the global table technique:
getfenv()[varname] = "hello"
Posted 14 December 2012 - 09:45 AM
going out on a limb here, but depending on what you're trying to achieve exactly, a table to store these dynamic variables might be more convenient. Simple program to demonstrate:
Again depends on what you're doing, but it can be safer than the global table approach which could end up clobbering things you might not want it to.
--table to hold variables with strings as names
local userVars={}
while true do
print("enter blank to exit")
write("variable name >")
local name=read()
if name=="" then
break
end
if userVars[name] then
print("current value of '"..name.."' is "..userVars[name])
end
write("New value:")
local val=read()
userVars[name]=val
print("value set.")
end
print("final values:")
for k,v in pairs(userVars) do
print(k.."=\""..v.."\"")
end
Again depends on what you're doing, but it can be safer than the global table approach which could end up clobbering things you might not want it to.
Posted 14 December 2012 - 10:05 AM
Gopher, i know what a table is, Im advanced at lua, my question was very specifically pointed against variables.
To Orwell: Thanks sense :)/>
To Orwell: Thanks sense :)/>
Posted 14 December 2012 - 10:12 AM
Oh, would that make
function makeVar(name)
return name
end
makeVar("lawl") = "herpaderp"
Posted 14 December 2012 - 10:54 AM
No, the function makeVar would just return the same string, not the variable with that name. Here is an example:Oh, would that makefunction makeVar(name) return name end makeVar("lawl") = "herpaderp"
function makeVar(varname, var)
getfenv()['varname']=var
end
makeVar("lawl","herpaderp")
or:
function makeVar(varname, var)
loadstring("return "..varname)() = var
end
makeVar("lawl","herpaderp")
Posted 14 December 2012 - 11:11 AM
Your first example looks plausible, but your second looks approximately equivalent to the code you're disagreeing with.
Posted 14 December 2012 - 11:58 AM
My second example is quite different from his though. He uses the parameter string as return value. While I use:Your first example looks plausible, but your second looks approximately equivalent to the code you're disagreeing with.
loadstring("return "..varname)()
These function calls give a reference to the variable with the name 'varname'. So if you return this, you return a reference to the variable with that name. Like this:
testVar = {"I am a table."}
local function getVar(varname)
return loadstring("return "..varname)()
end
alias = getVar("testVar")
alias == testVar -- True
Now the variable 'alias' is the exact same variable as 'testVar'. It's quite clear to me that Doyle's code would just make the variable 'alias' equal the string "testVar".
testVar = {"I am a table."}
local function getVar(varname)
return varname
end
alias = getVar("testVar")
alias == "testVar" -- True
Posted 21 December 2012 - 01:27 AM
Now, a week afterwards, I actually found a use for it, wondering if this code will work:
function varCheck(var, stan)
if var == nil then
loadstring("return "..var)() = stan
end
end
Posted 21 December 2012 - 01:46 AM
What?
You're concatenating a string and nil, trying to use that as an lua chunk in loadstring, calling the returned function, and setting that function = stan.
If you're trying to produce an error, then I think you've succeeded. But if you had something else in mind then perhaps not.
You're concatenating a string and nil, trying to use that as an lua chunk in loadstring, calling the returned function, and setting that function = stan.
If you're trying to produce an error, then I think you've succeeded. But if you had something else in mind then perhaps not.
Posted 21 December 2012 - 01:59 AM
It was made for checking if a variable is nil, if so, it would just make it equal to the variable passed by the second argument. But now, when you say it, I realise how dumb it looks. though "and setting that function = stan." isn't completely true, the function is called ;)/> I guess I would have to have var passed as a string and then loadstring that in the if statement to check if it's nil? and then my code would(hopefully?) work?
If someone with experience can lead me the way on this one, I would be ever so greatful
If someone with experience can lead me the way on this one, I would be ever so greatful
Posted 21 December 2012 - 04:18 AM
I tested this 2 days ago and I discovered that loadstring doesn't have access to the globals. So only the getfenv() method worked for me. I suggest dropping loadstring and using getfenv(). :)/> It's a cleaner method anyway.
Posted 21 December 2012 - 04:50 AM
OK Orwell, thanks ;)/> Can I get an explanation on getfenv() and it's uses?(Don't like using stuff I don't understand)
Posted 21 December 2012 - 05:47 AM
OK Orwell, thanks ;)/> Can I get an explanation on getfenv() and it's uses?(Don't like using stuff I don't understand)
getfenv([f])
Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.
Posted 21 December 2012 - 05:51 AM
getfenv() returns the environment table of the function it's being called from. setfenv( func, tEnv ) sets tEnv as the environment table for the function 'func'.
I'm not sure how much you know of this but the environment table is a table holding all global variables. The table key is the variable name, the value obviously is the variable value. (The main environment table is _G). So, let's take a look at this code:
Hmmm, sort of ninja'd by PixelToast. But _G is only the global table and won't always work. (e.g. os.run() gives the loaded program an empty environment table)
I'm not sure how much you know of this but the environment table is a table holding all global variables. The table key is the variable name, the value obviously is the variable value. (The main environment table is _G). So, let's take a look at this code:
local tEnv = getfenv() -- put the environment table for this function in tEnv
local printFunc = tEnv['print'] -- get the value for the key 'print' out of tEnv, it's a function pointer in this case
print( tostring( printFunc == print ) ) -- print the equality of the two function pointers
printFunc( tostring printFunc == print ) ) -- use the function pointer to call print
tEnv['print']("Test!") -- call the function pointer directly on the retreived env. table
getfenv()['print']("Test!") -- call the function pointer directly on the returned env. table from getfenv()
Hmmm, sort of ninja'd by PixelToast. But _G is only the global table and won't always work. (e.g. os.run() gives the loaded program an empty environment table)
Posted 21 December 2012 - 05:57 AM
you dont really want to use getfenv though
use
use
_G[string]=something
orpcall(setfenv(function() code end,setmetatable({[string]=something},getfenv()))
if you are worried about os.runPosted 21 December 2012 - 06:00 AM
Won't work in the case of os.run as I mentioned earlier.you dont really want to use getfenv though
use
_G[string]=something
Try this as a program:
x = "test"
print( _G["x"] )
That won't work because x won't be put in the global environment table, only in the one that the function has. (an empty one in the case of os.run)Posted 21 December 2012 - 06:01 AM
updated post-snip-
Won't work in the case of os.run as I mentioned earlier
Posted 21 December 2012 - 06:15 AM
That code is not even near flexible. Overriding the metatable of a function's environment table can be unwanted and isn't flexible at all. This code will get longer if you want to define multiple variables. And even then, he wants to access global variables defined somewhere else, not define new ones. And finally, you make a point of not using getfenv and then u use getfenv, setfenv and setmetatable… You can easily defineif you are worried about os.runpcall(setfenv(function() code end,setmetatable({[string]=something},getfenv()))
local G = getfenv()
at the top and use G from there on.Posted 21 December 2012 - 06:32 AM
OK, think I got it. will that make
a working version?
function varCheck(var, stan)
if var == nil then
getfenv()[var] = stan
end
end
a working version?
Posted 21 December 2012 - 06:35 AM
No, you are still indexing a nil value. You wanted to get a variable by it's name, right? Then it would be like this:OK, think I got it. will that makefunction varCheck(var, stan) if var == nil then getfenv()[var] = stan end end
a working version?
function varCheck(varName, stan)
getfenv()[varName] = getfenv()[varName] or stan
end
Posted 21 December 2012 - 06:36 AM
I very much doubt that nil is usable as an index.
Posted 21 December 2012 - 06:39 AM
oh yeah, to tired to think now. Thanks. Understand of all of that very well. Just being an idiot not thinking of it being passed as a string rather than a value.
Posted 21 December 2012 - 06:40 AM
Indeed, it isn't. That's why his function couldn't ever work, but mine would. Just be sure to pass the varName as a string.I very much doubt that nil is usable as an index.
Edit: ok, all is done then. :)/>
Posted 21 December 2012 - 07:21 AM
You have to admit, you didn't explain that varName was the string matching var's identifier. Though you did call it varName…which…does that count as an explanation? I can't tell.
I mean, I can see a tired Doyle trying to pass tostring(var) into the function as varName, which would be the wrong interpretation but consistent with what you said.
I mean, I can see a tired Doyle trying to pass tostring(var) into the function as varName, which would be the wrong interpretation but consistent with what you said.
Edited on 21 December 2012 - 06:23 AM
Posted 21 December 2012 - 07:25 AM
I thought it would have been clear from the numerous times I explained that earlier in this thread. I actually had the word string in the sentence earlier, but I couldn't get grammar right so I dropped it. :P/> Anyway, I wasn't clear, he didn't get something, asks for it, and I explain it better. It's how forums work.You have to admit, you didn't explain that varName was the string matching var's identifier. Though you did call it varName…which…does that count as an explanation? I can't tell.
Posted 21 December 2012 - 08:11 AM
Ideally. But this thread is full of "I shouldn't laugh because some of this is actually pretty difficult, but… :wacko:/> ".
I mean, I know I shouldn't laugh anyway, but sometimes I do.
Anyway, some of this really is just hard to get a handle on, no matter how well you explain it.
I mean, I know I shouldn't laugh anyway, but sometimes I do.
Anyway, some of this really is just hard to get a handle on, no matter how well you explain it.