Haha, everyone trips over this at least once. When I first encountered this, I was like WTF LUA HAZ BROKEN (similarly for Python), but it's actually a really intuitive design feature of Lua (Feature, not bug). http://failboat.me/2010/python-tip-copying-an-object/ for a little preview.
Basically, tables (and userdata) are stored as references to a memory location rather than as an actual array. For example, try the following example:
cache = {{1,1},{2,2}}
-- #Let's emulate a queue
cache[2] = cache[1]
cache[1][1] = 0; cache[1][2] = 0;
-- #Lee's magic goggle: cache = {{0,0},{0,0}}
-- #WTF?
-- #Let's try that again:
cache[1] = {1,1}
-- #Lee's magic goggle: cache = {{1,1},{0,0}}
The assignment operator automatically assigns the reference of the right-hand value to the left-hand variable. So the following happened:
Assume that we have the following memory blocks:
MEM - cache = x - MEM
MEM - x| cache[1] = y1 | cache[2] = y2 | - MEM
MEM - y1| cache[1][1] = z1 | cache[1][2] = z2 | - MEM - y2| cache[2][1] = z3 | cache[2][2] = z4 | - MEM
- cache[2] = cache[1] => cache[2] now points at y1
- cache[1][1] = y1+offset(1) = 0 => cache[1][1] now points at 0 (literals are not references), same for cache[1][2] = 0
- When we try to index cache[2][1], we go to the memory block that cache[2] points, which is y1, and then we increase its pointer by one, hence we have y1+offset(1), which from 2. is 0.
However, when we initiated a new table by writing {1,1}, we created a new location
w | w[1] | w[2]
so that:
1. cache[1] = {1,1} means that cache[1] now points to w.
2. Indexing cache[1][1] => w + offset(1) === w[1], which is 1.
3. If we change the value of cache[2][1], we only change y1[1], so cache[2][1] = the new value, but since w[1] is unchanged (w is at a different location), cache[1][1] is still 1.