I was trying to understand a Lua function to parse XML-formatted strings and I observed an unexpected behaviour on how tables were being handled. I summarised the problem as follows:
local stack = {}
local top = {}
table.insert(stack, top)
table.insert(top,{1,2,3})
top={'x','y','z'}
print(stack[1][1][1],stack[1][1][2],stack[1][1][3])
print(top[1],top[2],top[3])
>> 1 2 3
>> x y z
I don't get why the two outputs are not the same. If top is inserted into stack by reference, the first output would make sense if I didn't overwrite top with top={'x','y','z'}
. Why isn't stack affected when I directly enter the values of top?
It looks as if top={'x','y','z'}
created another sort of instance for top, in such a way that the values pointed by stack are being kept. Is this right? Lua documentation is scarce when you want to go into detail and I haven't found anything about this. It seems to me that this is a dangerous behaviour if it is not explicitly specified.
Regards
_______Edit:_______
I was making a mistake: table.insert(top,{1,2,3})
is not the same as top={'x','y','z'}
, it is the same as top[1]={'x','y','z'}
.
So, reformulating the original question, we have the code:
local stack = {}
local top = {}
table.insert(stack, top)
table.insert(top,{1,2,3})
top[1]={4,5,6} -- it does change stack
top = {'x'}
print(stack[1][1][1],stack[1][1][2],stack[1][1][3])
print(top[1][1],top[1][2],top[1][3])
>> 4 5 6
>> nil nil nil
Now, I see perfectly normal the second output, but I still have doubts predicting the first one.
If I replace top = {'x'}
for top[1] = 'x'
the output turns to
>> nil nil nil
>> nil nil nil
I have read the Values and Types section, but I still don't fully know what's wrong. Sorry if I am making a silly mistake, but I can't see it.
Tables are values in Lua. Each table is a separate and distinct value. Variables are not names for values; they're just boxes that hold them for a time.
Multiple variables can refer to the same table. So after doing
top = {}
, the variabletop
has a reference to a table. By doingtable.insert(stack, top)
, now bothtop
andstack[1]
have a reference to the same table.If you execute
top = {'x'}
, then you change what table is stored intop
. You have put a new thing in that box. Butstack[1]
still refers to the table that was set into it.It's not different from doing this:
var2
is still five; it didn't become 10.var2
has no connection tovar1
. It simply took the value thatvar1
had at that time.Where you're getting confused is in the difference between the table itself and its contents.
top
contains a reference to a table.top[1]
means to get the first element of the table referenced bytop
. If you assign something totop[1]
, you are not modifying the variable; you are modifying the contents of the table referenced by that variable.top[1] = {4, 5, 6}
modifies what is stored in the table currently referenced bytop
. And at that time, that table is also being referenced bystack[1]
. Therefore, you can access that table throughtop
or throughstack
.Once you change what table
top
references, by doingtop = {'x'}
, that is no longer true.top
now references a different table. But the table it used to reference is still accessible viastack
.