How are tables managed in Lua? [Example of extrange behaviour]

124 views Asked by At

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.

2

There are 2 answers

2
Nicol Bolas On BEST ANSWER

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 variable top has a reference to a table. By doing table.insert(stack, top), now both top and stack[1] have a reference to the same table.

If you execute top = {'x'}, then you change what table is stored in top. You have put a new thing in that box. But stack[1] still refers to the table that was set into it.

It's not different from doing this:

var1 = 5;
var2 = var1;
var1 = 10;

var2 is still five; it didn't become 10. var2 has no connection to var1. It simply took the value that var1 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 by top. If you assign something to top[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 by top. And at that time, that table is also being referenced by stack[1]. Therefore, you can access that table through top or through stack.

Once you change what table top references, by doing top = {'x'}, that is no longer true. top now references a different table. But the table it used to reference is still accessible via stack.

2
lhf On

Lua operates on values, not on variables.

Try replacing

top={'x','y','z'}

by

top[2]='y'