Jump to content




Loading strings for variable naming


  • You cannot reply to this topic
28 replies to this topic

#1 Doyle3694

  • Members
  • 815 posts

Posted 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?

#2 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

Posted 14 December 2012 - 07:55 AM

Indeed, loadstring returns a function. But you can use it like 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.

#3 Doyle3694

  • Members
  • 815 posts

Posted 14 December 2012 - 08:39 AM

Can I do
local loadstring(var) = "hello"
?

#4 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

Posted 14 December 2012 - 09:30 AM

View PostDoyle3694, on 14 December 2012 - 08:39 AM, said:

Can I do
local loadstring(var) = "hello"
?
No, it would still be:
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"


#5 GopherAtl

  • Members
  • 888 posts

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:

--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.

#6 Doyle3694

  • Members
  • 815 posts

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 :)

#7 Doyle3694

  • Members
  • 815 posts

Posted 14 December 2012 - 10:12 AM

Oh, would that make
function makeVar(name)
   return name
end
makeVar("lawl") = "herpaderp"


#8 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

Posted 14 December 2012 - 10:54 AM

View PostDoyle3694, on 14 December 2012 - 10:12 AM, said:

Oh, would that make
function makeVar(name)
   return name
end
makeVar("lawl") = "herpaderp"
No, the function makeVar would just return the same string, not the variable with that name. Here is an example:
function makeVar(varname, var)
  getfenv()['varname']=var
end
makeVar("lawl","herpaderp")
or:
function makeVar(varname, var)
  loadstring("return "..varname)() = var
end
makeVar("lawl","herpaderp")


#9 Lyqyd

    Lua Liquidator

  • Moderators
  • 8,465 posts

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.

#10 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

Posted 14 December 2012 - 11:58 AM

View PostLyqyd, on 14 December 2012 - 11:11 AM, said:

Your first example looks plausible, but your second looks approximately equivalent to the code you're disagreeing with.
My second example is quite different from his though. He uses the parameter string as return value. While I use:
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


#11 Doyle3694

  • Members
  • 815 posts

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									  


#12 ChunLing

  • Members
  • 2,027 posts

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.

#13 Doyle3694

  • Members
  • 815 posts

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

#14 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

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.

#15 Doyle3694

  • Members
  • 815 posts

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)

#16 PixelToast

  • Signature Abuser
  • 2,265 posts
  • Location3232235883

Posted 21 December 2012 - 05:47 AM

View PostDoyle3694, on 21 December 2012 - 04:50 AM, said:

OK Orwell, thanks ;) Can I get an explanation on getfenv() and it's uses?(Don't like using stuff I don't understand)

Quote

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.


#17 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

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:
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)

#18 PixelToast

  • Signature Abuser
  • 2,265 posts
  • Location3232235883

Posted 21 December 2012 - 05:57 AM

you dont really want to use getfenv though
use
_G[string]=something
or
pcall(setfenv(function() code end,setmetatable({[string]=something},getfenv()))
if you are worried about os.run

#19 Orwell

    Self-Destructive

  • Members
  • 1,091 posts

Posted 21 December 2012 - 06:00 AM

View PostPixelToast, on 21 December 2012 - 05:57 AM, said:

you dont really want to use getfenv though
use
_G[string]=something
Won't work in the case of os.run as I mentioned earlier.
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)

#20 PixelToast

  • Signature Abuser
  • 2,265 posts
  • Location3232235883

Posted 21 December 2012 - 06:01 AM

View PostOrwell, on 21 December 2012 - 06:00 AM, said:

-snip-
Won't work in the case of os.run as I mentioned earlier
updated post





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users