table.remove in lua acting weirdly - lua

tbl1 = {1}
tbl2 = tbl1
table.remove(tbl2,1)
print(tbl1[1])
-- >> nill
The above example is a simplification of the problem in my code, by removing a index from tbl2, it also removes from tbl1, is there a reason for this to be happening?

Variables in Lua are references to objects, and so a=b sets the variable named a to refer to the object that b refers to. If b is a table, then after the assignment both a and b point to the same table object.

Related

Lua key conflict with array index

I am a newbie two lua. Recently I learned about Table in lua.
In my view (I am not sure whether it is right),
table can be used as Array as well as Map. When used as Map, values without keys automatically get ordinal index.
t1 = {"a", "b"}
t2 = {"a", [2] = "b"}
It is true for both t1 and t2 that tX[1] == "a" and tX[2] == "b", where X is 1 or 2.
It get confusing when automatically assigned index and named key are in conflict, which is
t3 = {"a", [1] = "b"}
in this case t3[1] == "a" and t3[2] == nil. and no warns or errors were arose.
I guessed "b" may overwrite "a" in index 1, but it is not.
So what is the principle in this situation ?
Lua keeps the flexibility of TABLE structure. Though this gives table much more possiblity and capability, it also involves some confusion. What's the main notion of such design ?
Refer to Reference Manual: 3.4.9 - Table Constructors; you are interested in:
Fields of the form exp are equivalent to [i] = exp, where i are consecutive integers starting with 1; fields in the other formats do not affect this counting.
and:
The order of the assignments in a constructor is undefined. (This order would be relevant only when there are repeated keys.)

Strange bug with table in lua

I'm adding a string to a table in lua. When I use the table in a function the original table is getting altered. I'm only a beginner but I thought that the function could not do that because it is outside of it's scope. Is there something obvious I'm missing?
local testTable= {}
testTable.name = {}
testTable.name[1] = "Jon"
print(testTable.name[1])
local function testFunc(a)
a.name[1] = "Bob"
end
local newTable = testTable
testFunc(newTable)
print(testTable.name[1])
I expected the output to be:
Jon
Jon
The actual output is:
Jon
Bob
How can the testFunc change the testTable?
You assign testTable's address to newTable, so testTable and newTable point to the same table.
If you want to output be
Jon
Jon
You should copy the table when you assign newTable.
You can copy the table like this function:
function table.copy(old)
local new = {}
for k, v in pairs(old) do
new[k] = v
end
return new
end
When I use the table in a function the original table is getting altered. ... I thought that the function could not do that because it is outside of it's scope.
Local variables have their own scope, but tables do not. Two things to remember:
Variables store references, not values. (This only makes a difference for mutable values.)
Tables are mutable, i.e., they can be changed internally.
Breaking it down:
local newTable = testTable
In this line, you're assigning one variable to another, so both variables refer to the same table.
We mutate a table by assigning to an index within that table, so testFunc alters whatever a (actually a.name) refers to. This is handy, because it allows us to write functions that mutate tables that we pass as arguments.
The following function does nothing, like you would expect, because it assigns a new table to the bare name a (which happens to be a local variable):
local function doNothing(a)
a = {name = {'Bob'}}
end

Metatable issue

So I know that lua will look to a table's metatable if it doesn't contain the variable I reference, but it seems wrong that when I attempt to set a variable that doesn't exist yet in a table it sets it in the metatable instead.
Heres an example of what i mean
a = {__index = {tbl1 = {var = 1}, tbl2 = {var = 2}}}
b = setmetatable({}, a)
print(b.tbl1.var, a.__index.tbl1.var)
b.tbl1.var = 2
print(b.tbl1.var, a.__index.tbl1.var)
In this code it will replace the metatables variable instead of setting it in the table im referencing.
However this does not occur with this code
a = {__index = {4, 5, 6}}
b = setmetatable({}, a)
print(b[1], a.__index[1])
b[1] = 2
print(b[1], a.__index[1])
Is there more work needed when using metatables and nested tables?
Or is there a way around this?
In this code it will replace the metatables variable instead of setting it in the table im referencing.
I think this is to be expected; the code retrieves tbl1 key and sets a field in the table associated with that key. The key doesn't exist in the table, only in the metatable, so that's where it's set. If you add the same key in the table b = setmetatable({tbl1 = {}}, a), you'll see that the value is set in that table.
Is there more work needed when using metatables and nested tables? Or is there a way around this?
I'm not sure what result you expect. Lua doesn't do autovivification, which would make tbl.foo = 1 to create table tbl if it didn't already exist. If the field tbl1 is already present in the table, the the behavior is exactly what you'd expect. If it's present in the metatable, and you modify its field, this is exactly where it's going to be modified.

Lua table continues to be empty, even though I am giving it stuff

In my Lua-powered game, I am trying to create an Explorer to see all the instances that have been created. I've created a function inside my DataModel "class" (as I like to call it) that will scan the children of an item, and put it neatly inside a table.
function DataModel.ObjectToTable(obj)
children = {}
for i,v in pairs(obj:GetChildren()) do
table.insert(children, DataModel.ObjectToTable(v))
end
print(obj.Name)
dmyself = {}
dmyself.Name = obj.Name
dmyself.Object = obj
dmyself.Children = children
print(#dmyself)
return dmyself
end
The issue is that, the print(#dmyself) is coming out as 0. But as you can see, I just set 3 things inside of it. What could cause such a thing to happen? Am I doing something obviously wrong?
The print(obj.Name) line is returning what it should. I am simply stuck on 'dmyself'.
# is the length of the array part of the Lua table; it only takes integer keys into account. More specifically,
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value.
If you use pairs, you can see that your table is not empty. But since there's nothing in the array part of the table, it's length is zero.

Assign table to table in Lua

In Lua, I can add an entry inside table with table.insert(tableName, XYZ). Is there a way I can add already existing table into table? I mean a directly call rather then traversing and add it.
Thanks
The insert in your example will work fine with whatever contents happen to be inside the XYZ variable (number, string, table, function, etc.).
That will not copy the table though it will insert the actual table. If you want to insert a copy of the table then you need to traverse it and insert the contents.
First: In general, you do not need table.insert to put new entries into tables.
A table in Lua is a collection of key-value pairs; entries can be made like this:
local t = {} --the table
local key= "name"
local value = "Charlie"
t[key] = value --make a new entry (replace an existing value at the same key!)
print(t.name) --> "Charlie"
Note that key can have any type (not just integer/string)!
Very often you will need tables for a simple special case of this: A sequence ("list", "array") of values. For Lua, this means you want a table where all the keys are consecutive integers, and contain all non-nil values. The table.insert function is intended for that special case: It allows you to insert a value at a certain position (or to append it at the end of the sequence if no position is specified):
local t = {"a", "b", "d"} --a sequence containing three strings (t[1] = "a", ...)
table.insert(t, "e") --append "e" to the sequence
table.insert(t, 3, "c") --insert "c" at index 3 (moving values at higher indices)
--print the whole sequence
for i=1,#t do
print(t[i])
end
If I understand what you mean correctly, you want to do this:
local t1 = {1, 2, 3}
local t2 = {4, 5, 6}
some_function(t1, t2)
-- t1 is now {1, 2, 3, 4, 5, 6}
There is indeed no way to do this without iterating t2. Here is a way to write some_function:
local some_function = function(t1, t2)
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
end
No, you must copy the second table's key/value pairs into the first table. Copying the existing values from the second table is what's known as a "shallow copy." The first table will reference the same objects as the second table.
This works under limited circumstances:
local n = #t1
for i=1,#t2 do t1[n+i] = t2[i] end
It does attempt to shift the t2 elements to just beyond the existing t1 elements. That could be a vital requirement but wasn't stated in the question.
It has a few of problems, though:
By using #t1 and #t2, it misses keys that aren't positive integers and can miss keys that are integers greater than a skipped integer key (i.e. never assigned or assigned nil).
It accesses the first table with an indexer so could invoke the __newindex metamethod. That probably wouldn't be desirable when only copying is wanted.
It accesses the second table with an indexer so could invoke the __index metamethod. That wouldn't be desirable when only copying is wanted.
You might think that ipairs could be used if only positive integer keys are wanted but it quits on the first nil value found so could miss even more than #t2 does.
Use pairs instead:
for key, value in pairs(t2) do
rawset( t1, key, value )
end
If you do want to avoid replacing existing t1 values when the keys match or otherwise map t2 keys in some way then that has to be defined in the requirements.
Bottom line: pairs is the way to get all the keys. It effectively does a rawget so it avoids invoking __index. rawset is the way to do a copy without invoking __newindex.

Resources