Loadstring() not working with variables inside a script?

I need to query the contents of any variable that is currently in my script, through Roblox Player, by typing the name of this variable inside a TextBox.

As Roblox Player is very limited for debugging (and Studio often doesn’t allow debugging, eg Teleport), I’m trying to create a system to query the value of variables that will be typed during a TextBox and sent to the server, which should be processed using loadstring.
But for some reason loadstring is not seeing these variables.

Edit

Actually, the real example is here: Loadstring() not working with variables inside a script? - #7 by rogeriodec_games


function Dbg(var)
	print(var)
	loadstring('print(var)')()
end

Dbg(123)

Will print:

  123
  nil

What’s wrong?

1 Like

Try:

loadstring('function Dbg(var) print(var) end Dbg(123')()

(btw this was written late in night)

1 Like

Simple fix

function Dbg(var)
	print(var)
    local code = 'print(%s)'
	loadstring(code:format(var))()
end

Dbg(123)
3 Likes

Thanks, your solution works, but I think this can be more intuitive:

function Dbg(var)
	loadstring('print(' .. var .. ')')()
end

Dbg(123)

Will print:

123

1 Like

This example is not working.


Oh, i’ll remove it! char lim!!

@Synitx @CodedJer
I beg your pardon, the OP was not right:

Actually I need to pass the NAME OF THE VARIABLE to be consulted as an argument.
But in the example below, I’m just getting nil.

local VarA = 123

function Dbg(VarName)
	local VarB = 'abc'
	print(VarName)
	loadstring('print(VarName)')()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

VarA
nil
VarB
nil

What is wrong?

You can replace %s in a string with anything you want.
Example:

local str = "Hello %s"
local hiRoblox = str:format("Roblox") -- Replaces %s with Roblox

print(hiRoblox) -- Hello Roblox

So with your code, you can do

local VarA = 123

function Dbg(VarName)
	local VarB = 'abc'
	print(VarName)
    local code = 'print(%s)'
	loadstring(code:format(VarName))()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

Thanks, but your code still prints:

VarA
nil
VarB
nil

Tried out their code and it works when I incase the %s in single quotes or double quotes, though since single quotes are used you’d need to use double quotes or escape single quotes

local VarA = 123

function Dbg(VarName)
	local VarB = 'abc'
	print(VarName)
    local code = 'print("%s")' -- \' can work instead of " as well
	loadstring(code:format(VarName))()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

Unless the online compiler I use and LuaU handle loadstring differently

It’s printing:

VarA
VarA
VarB
VarB

But I need to print the CONTENT OF THE VARIABLE, not the name.
It should print:

VarA
123
VarB
abc

Is it possible to instead have a dictionary or variables to get from instead of having them split up?

local vars = {
    ["VarA"] = 123,
    ["VarB"] = 'abc'
}

function Dbg(VarName)
	print(VarName)
    local code = 'print("%s")'
	loadstring(code:format(vars[VarName]))()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

This does what you want it to, though if you can’t have it be a dictionary, then I’m uncertain as to how you can do that

1 Like

No. As I said in the OP, I need to query the contents of any variable that is currently in my script, through Roblox Player, by typing the name of this variable inside a TextBox.

From what I looked up, you can use getfenv to get the variable by it’s name

local VarA = 123

function Dbg(VarName)
	local VarB = 'abc'
	print(VarName)
    local code = 'print(getfenv()["%s"])' -- \' can work instead of " as well
	loadstring(code:format(VarName))()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

Though this still wont work because to get the variables you need to make the variables global, meaning removing the local from the ones you want to access

VarA = 123

function Dbg(VarName)
	VarB = 'abc'
	print(VarName)
    local code = 'print(getfenv()["%s"])' -- \' can work instead of " as well
	loadstring(code:format(VarName))()
end

Dbg('VarA') -- must show to content of VarA
Dbg('VarB') -- must show to content of VarB

There’s no way around this as global and local variables are stored differently, and getfenv only gets things global in the environment, though not sure if anything recent happened on Roblox that allows local variables to be retrieved, but from my knowledge I don’t think so, meaning you either have to make the variables to retrieve global or find another way to do it

1 Like
var = "Hello world!"

local function getSetVar(varName, varVal)
	local env = getfenv()
	if varVal then env[varName] = varVal setfenv(0, env) end
	return env[varName]
end

local varVal = getSetVar("var") --varName, [varVal]
print(varVal) --Hello world!

varVal = getSetVar("var", "foobar")
print(varVal) --foobar

This doesn’t seem like a necessary use case for loadstring() as the function is static. loadstring() should be used in instances where the function passed (as a string) is subject to change.

The following is a valid use case for loadstring(), of which I have encountered before (Game’s ‘Roblox Battle’).

local Game = game
local Players = Game:GetService("Players")

local Admins = {
	[1] = true,
	--Insert admins here.
}

local function OnPlayerAdded(Player)
	local function OnPlayerChatted(Message)
		if not Admins[Player.UserId] then return end
		local Function = loadstring(Message)
		Function()
	end
	
	Player.Chatted:Connect(OnPlayerChatted)
end

Players.PlayerAdded:Connect(OnPlayerAdded)

It should be noted that loadstring() isn’t called in protected mode, meaning that if it errors, those errors are propogated to the caller (the function that called loadstring()).

3 Likes

You can pass values to the function created with loadstring, if you only want to access a specific set of values:

local function Dbg(Var)
	print(Var)
	loadstring"print(...)"(Var)
	-- ... is an expression which expands to all variadic arguments,
	-- and the function returned by loadstring is a variadic function
	-- with no named arguments
end
Dbg(123)

There is no way to directly access or modify the local variables visible to the function that called loadstring. loadstring will not see the variables because it is compiling a new program, it isn’t looking into the function that called it to look for the local variables and their names.

I actually have a thread explaining this. Have a look.

TL;DR: Use global variables (albeit it is discouraged), or use the functions getfenv() or setfenv() to literally modify the loadstring’s function’s environment.

1 Like

Thanks. Your example works, but not for tables.
So I got a final solution, based on getfenv() in which can use from a single variable to a reference to several levels of a table:

Tab = {L1 = {L2 = {Value = 123}}}

function Dbg(VarName)
	local Var = VarName:split('.')
	local Value = getfenv()
	for i in ipairs(Var) do
		Value = Value[Var[i]]
	end
	print(VarName .. ':', Value)
end

Dbg('Tab.L1.L2.Value')

Will print:

Tab.L1.L2.Value: 123

You also could easily just pass arguments into the loadstrings function params, loadstring is used to create a function from a given source, Most people commonly mistaken that for just running code wherever and whenever.

function Dbg(VarName)
	local VarB = 'abc'
	print(VarName)
	loadstring([[
    local VarName = ...
    print(VarName)
    ]])(VarName)
end
Dbg("Data") -- Will print "Data"

-- To simplify a bit
function Dbg(VarName)
    Func = loadstring('local VarName = ...; print(VarName)')
    Func(VarName)
end

Dbg("Data") -- Will print "Data"

Same method would work for tables

function Dbg(VarName)
    Func = loadstring('local VarName = ...; print(VarName)') -- Everything after the ; can be changed to your liking to use the variable.
    Func(VarName)
end

Dbg({"1","2"}) -- Will print the given table