I was working on some code that involved copying indexed tables, and
noticed that copying an indexed table T1 that was missing a [1] key (so that #T1
== 0) yielded a table T2 that would return the length as if the [1] key were in
T2. Below is the simplest code that I could get to reproduce this. Removing any
of the keys 2, 3, or 4 from T1 makes both tables return a size of 0, but adding
additional keys after 4 to T1 simply causes T2 to reflect the new highest
key.

----------------------------------------

T1={

[2]={},

[3]={},

[4]={},

}

T2 = {}

for k, v in pairs(T1) do

T2[k] = v

end

print(#T1, #T2)

assert(#T1 == #T2) -- will fail

----------------------------------------

After playing around a bit more, I discovered that this occurs with all
dynamically generated tables. The following is the simplest demonstration of
this

----------------------------------------

T1={}

for i = 2, 4 do

T1[i] = {}

end

print(#T1)

----------------------------------------

However, there seems to be some strange pattern that determines the number
of keys that must be in the table for the size to not equal 0, and it depends on
the first key in the table (the closest one to 1). This is demonstrated below
(the first number printed is the first key and the second number is the last
key, e.g. 2 and 4 with the first example in this message). Change the max for
initial as high as you wish to see this pattern extend on. When looking at it, I
realized that when the max key is a power of 2 (256, 512, 1024, blah blah), the
next max key jump up to a number much higher than the last. Also at these powers
of 2, the max key is double the min key.

----------------------------------------

for initial = 2, 100 do

local size = 0

while true do

size = size + 1

T1={}

for key = initial, initial+size
do

T1[key]
= true

end

if #T1 ~=0 then

print(initial, initial+size)

break

end

end

end

----------------------------------------

In fact, when you only look for these numbers, the results are quite
pretty

----------------------------------------

initial = 2

while true do

if floor(log(initial)/log(2)) == log(initial)/log(2)
then -- an exact power of 2

local size = initial*2 -
initial

T1={}

for key = initial, initial+size
do

T1[key]
= true

end

if #T1 ~=0 then

print(initial, initial+size)

end

end

initial = initial*2

collectgarbage("collect") -- collecting garbage allows
for one more iteration before we run out of memory

end

----------------------------------------

I don’t know why any of this is happening, but it seems extremely buggy to
me. Why are my tables that are missing a [1] key returning a size? ipairs() will
not traverse them, but (for i=1, #table) will? This should not be.