I came across a problem while writing some code up for a game. It seems I can't use variables in statements like;
local Username = "Cranavvo"
game.Players.Username:BreakJoints() -- Kills the player
And the output is telling me "No such user as 'Username'" which should be "Cranavvo".
From Lua PiL on tables
To represent records, you use the field name as an index. Lua supports
this representation by providing a.name as syntactic sugar for
a["name"].
A common mistake for beginners is to confuse a.x with a[x]. The first
form represents a["x"], that is, a table indexed by the string "x".
Therefore, when you try:
game.Players.Username:BreakJoints()
Lua interprets it as:
game["Players"]["Username"]:BreakJoints()
which ofcourse is wrong. If you want to use varying name as index for a table, use them like this:
local foo = "Cranavvo"
game.Players[foo]:BreakJoints()
But to be mentioned is that the Player class do not have a BreakJoints method, you have to get the character model with help of the .Character attribute like this:
local foo = "Cranavvo"
game.Players[foo].Character:BreakJoints()
Also to be mentioned is that if the player with that name does not exist the code will break, and also that the character can be null, in which case it also breaks. Thus you need to add some error handling. Like this:
local foo = "Cranavvo"
local Player = game.Players:findFirstChild(foo)
if Player ~= nil and Player.Character ~= nil then
Player.Character:BreakJoints()
end
The correct way to do this in roblox is this:
local Username = "Cranavvo"
local p = game.Players:FindFirstChild(Username)
if(p ~= nil) then
if(p.Character ~= nil) then
p.Character:BreakJoints()
end
end
Double check if the user really exists at the time your code gets executed.
Also it should be:
game.Players.Username:BreakJoints()
EDIT:
I misread what you wanted to do:
in
...Players.Username
lua interprets Username as a named index and does not use the Username variable declared beforehand.
If you want to access an array variable with a dynamic name you can do it like this:
game.Players[Username]:BreakJoints()
additionally in roblox you could just use the following:
game.Players:GetPlayerByID(userId):BreakJoints()
Variables are very confusing in Lua sometimes.
For example, there are global and local variables.
Local variables are variables that can be forgotten/erased after the operation ends: local x = 2
Global variables are variables that stay within the game/application unforgotten, this is good with high scores and other neat things. x = 2 (Notice there isn't a "local" statement)
Related
I'm a beginner at Lua and programming in general (I've had some experience in other languages but nothing huge) and I've been following a tutorial where there's this one exercise on tables:
"Make a function with a table in it, where each key in the table is an animal name. Give each key a value equal to the sound the animal makes and return the animal sound. Try invoking the function and see if you get back the correct sound."
Here's my current solution:
make_sound = function(input)
animal_sounds = {
["cat"] = "meow",
["dog"] = "woof"
}
return animal_sounds.input
end
print(make_sound("cat"))
This just prints 'nil'. I've tried so many variations of this but they all either print 'nil' as well or give me an error saying something about nil (sorry I can't remember the original message or erroneous code).
I know this is a really dumb question and probably has an extremely basic answer so I'm sorry for my stupidity. All the other exercises have been a breeze and then I suddenly get hit with this thing for an hour. I searched everywhere but could only find results about functions inside arrays or something else completely. I didn't want to just give up on a seemingly easy task so here I am...
If your function returns the whole animal_sounds table, though it is not what is asked of you, you get the animal sound by print(make_sound().cat):
make_sound is a function,
make_sound() returns a table,
make_sound()['cat'] is a field of that table,
and make_sound().cat is syntactic sugar for it, as is said in the answer above.
Also, better declare everything local, including function make_sound and animal_sounds table.
And you can skip [""]/[''] in table keys, if they are strings of basic Latin, numbers and underscores: cat = 'mew' not ['cat'] = 'mew'.
Unless you are going to use make_sound as a variable, it is better to declare it with local function syntax, rather than an assignment.
You can skip parentheses around the only string or table parametre in the function call: f'str' rather than f( 'str' ).
Most imporantly, your function never uses input, which is supposed to be the animal. Therefore, it has to return not the table, but the sound. So, move the [] part inside the function.
So:
local function make_sound( input )
local animal_sounds = {
cat = 'meow',
dog = 'woof',
cow = 'moo'
}
return animal_sounds[input]
end
print( make_sound 'cat' )
P.S. You can even make the table anonymous, though it will need to be surrounded with parentheses, otherwise Lua will think that return is not the last operator before end as it should be:
local function make_sound( input )
return ({
cat = 'meow',
dog = 'woof',
cow = 'moo'
})[input]
end
print( make_sound 'cat' )
Try this:
return animal_sounds[input]
The animal_sounds.input is equivalent to animal_sounds["input"] and your table does not have the "input" key, hence it returns nil.
I have actually been wondering about this question for a long time, and I can recall reading something somewhere on the internet about loading all local variables into a table, but I could never find it again.
What I am wondering is if there is basically any way to dynamically create a local variable, similar to how you can dynamically create a global variable.
In Lua you can create dynamic global variables simply by saying:
local my_env = getfenv(1);
for i = 1, 10 do
my_env["OMG_DYNAMIC_GLOBAL_VARIABLE_"..i] = i * i;
end
But I have always wondered if there is a way to essentially do the same or a similar thing for local variables. Something like
for i = 1, 10 do
local["OMG_DYNAMIC_LOCAL_VARIABLE_"..i] = i * i;
end
would kind of be pseudo code for what I am trying to do.
As a second part to my question, I am wondering if there is any way to possibly iterate through every local variable in the current scope? I guess pseudo code for what I am trying to do would look something like:
local a = 123;
local b = 321;
LocalVars = {(local)}; --the table with the local variables in it.
for i,v in pairs(LocalVars) do print(i, v); end
I would appreciate any help regarding either part of my question.
Thanks
the table with the local variables in it
There is no table with local variables. Local variables do not exist in compiled Lua. There are simply locations on the Lua stack and/or upvalues. Even the names of local variables are lost during the compilation process.
Local variables are always static constructs of the Lua source code. They never exist within a table. If you need a non-static construct, use a table. That's what tables are for. That's (part of) why Lua globals are in a table.
I don't see the advantage of what you proposed over a regular local table except for syntactic sugar.
local locals = {}
locals.a = 123
locals.b = 321
for i,v in pairs(locals) do
print(i, v)
end
The syntax you proposed does not make the program clearer or easier to read in any way. In fact it even creates new problems. Does the following print c as well or does it not because it is in a nested local scope?
for i,v in pairs(LocalVars) do
local c = 1729
print(i, v)
end
I need to create many variables, and I want to do declare these variable's name by function. In like this:
function DefineVariable(VariableName)
return VariableName = 123 end
What i want from the function is:
DefineVariable(weg423)
-- Result: weg423 = 123
But it was not easy as I thought... That function does not worked. I want to know how to turn it into working function.
And, could i receive an answer about this too?
a = "blahblah"
...somehow...
DefineVarByValue(a)
-- Result: blahblah = 123
Ah and one more question. how to change 'table variable' to 'string or number variable'? (i mean the 'number expected, got table' error...)
All simple types in Lua are passed by value, so your DefineVariable function gets the current value of the variable weg423 and not the name of it, which means you can't change the value of weg423 from the function.
If this is a global variable, then you can pass the name of that variable (for example, DefineVariable('weg423')) and the function can then change the value of that variable by referencing it as a key in _G or _ENV table (_G[VariableName] = whatever).
I still don't see a point in doing it this way. There is nothing wrong with using weg423 = 123.
In Programming in Lua (3rd Ed.) by Roberto Ierusalimschy it is stated that
A common idiom in Lua is
local foo = foo
This code creates a local
variable, foo, and initializes it with the value of the global
variable foo. (The local foo becomes visible only after its
declaration.) This idiom is useful when the chunk needs to preserve
the original value of foo even if later some other function changes
the value of the global foo; it also speeds up the access to foo.
Could someone explain this more in detail and provide a simple example?
At the moment, the only use I can think of for this idiom is to manage local variables (in a given block) that have the same names as global variables, so that the global variable is left unchanged after the block.
An example:
foo = 10
do
local foo = foo
foo = math.log10(foo)
print(foo)
end
print(foo)
this gives:
1
10
But the same could be accomplished without using the idiom at all:
bar = 10
do
local bar = math.log10(bar)
print(bar)
end
print(bar)
that gives the same result. So my explanation doesn't seem to hold.
I've seen this used more often as a optimization technique than as a way to preserve original values. With the standard Lua interpreter, every global variable access and module access requires a table lookup. Local variables, on the other hand, have statically-known locations at bytecode-compile time and can be placed in VM registers.
In more depth: Why are local variables accessed faster than global variables in lua?
The explanation is correct; I'm not sure why you are not satisfied with your example. To give you a real example:
local setfenv = setfenv
if not setfenv then -- Lua 5.2+
setfenv = function() ..... end
end
Another reason is to preserve the value as it is at this moment, so that other functions that use that value (in a file or a module) would have the same expectations about that value.
Wrapping a global:
do
local setmetatable = setmetatable
function _ENV.setmetatable(...)
-- Do your thing
return setmetatable(...)
end
end
Reducing overhead by using a local instead of doing a lookup in the globals-table (which is a local btw.):
local type = type
for k, v in next, bigtable do
if type(v) == "string" then
-- Do one thing
else
-- Do other thing
end
end
I think you're splitting hairs, unintentionally.
local bar = math.log10(bar)
is essentially the same as local bar = bar in spirit, but we it would be less useful to claim that the idiom is local bar = a(bar), because we may want to handle the local in some way other than passing it to a function first -- e.g. appending it to something.
This point is that we want to refer to the local bar, just as you say, not exactly how the conversion from global to local is done.
Sorry if this is too obvious, but I am a total newcomer to lua, and I can't find it in the reference.
Is there a NAME_OF_FUNCTION function in Lua, that given a function gives me its name so that I can index a table with it? Reason I want this is that I want to do something like this:
local M = {}
local function export(...)
for x in ...
M[NAME_OF_FUNCTION(x)] = x
end
end
local function fun1(...)
...
end
local function fun2(...)
...
end
.
.
.
export(fun1, fun2, ...)
return M
There simply is no such function. I guess there is no such function, as functions are first class citizens. So a function is just a value like any other, referenced to by variable. Hence the NAME_OF_FUNCTION function wouldn't be very useful, as the same function can have many variable pointing to it, or none.
You could emulate one for global functions, or functions in a table by looping through the table (arbitrary or _G), checking if the value equals x. If so you have found the function name.
a=function() print"fun a" end
b=function() print"fun b" end
t={
a=a,
c=b
}
function NameOfFunctionIn(fun,t) --returns the name of a function pointed to by fun in table t
for k,v in pairs(t) do
if v==fun then return k end
end
end
print(NameOfFunctionIn(a,t)) -- prints a, in t
print(NameOfFunctionIn(b,t)) -- prints c
print(NameOfFunctionIn(b,_G)) -- prints b, because b in the global table is b. Kind of a NOOP here really.
Another approach would be to wrap functions in a table, and have a metatable set up that calls the function, like this:
fun1={
fun=function(self,...)
print("Hello from "..self.name)
print("Arguments received:")
for k,v in pairs{...} do print(k,v) end
end,
name="fun1"
}
fun_mt={
__call=function(t,...)
t.fun(t,...)
end,
__tostring=function(t)
return t.name
end
}
setmetatable(fun1,fun_mt)
fun1('foo')
print(fun1) -- or print(tostring(fun1))
This will be a bit slower than using bare functions because of the metatable lookup. And it will not prevent anyone from changing the name of the function in the state, changing the name of the function in the table containing it, changing the function, etc etc, so it's not tamper proof. You could also strip the tables of just by indexing like fun1.fun which might be good if you export it as a module, but you loose the naming and other tricks you could put into the metatable.
Technically this is possible, here's an implementation of the export() function:
function export(...)
local env = getfenv(2);
local funcs = {...};
for i=1, select("#", ...) do
local func = funcs[i];
for local_index = 1, math.huge do
local local_name, local_value = debug.getlocal(2, local_index);
if not local_name then
break;
end
if local_value == func then
env[local_name] = local_value;
break;
end
end
end
return env;
end
It uses the debug API, would require some changes for Lua 5.2, and finally I don't necessarily endorse it as a good way to write modules, I'm just answering the question quite literally.
Try this:
http://pgl.yoyo.org/luai/i/tostring
tostring( x ) should hopefully be what you are looking for
If I am not wrong (and I probably will, because I actually never programmed in Lua, just read a bunch of papers and articles), internally there is already a table with function names (like locals and globals in Python), so you should be able to perform a reverse-lookup to see what key matches a function reference.
Anyway, just speculating.
But the fact is that looking at your code, you already know the name of the functions, so you are free to construct the table. If you want to be less error prone, it would be easier to use the name of the function to get the function reference (with eval or something like that) than the other way around.