# Possible bug relating to table sizes Classic List Threaded 4 messages Reply | Threaded
Open this post in threaded view
|

## Possible bug relating to table sizes

 I was working on some code that involved copying indexed tables, and noticed that copying an indexed table T1 that was missing a  key (so that #T1 == 0) yielded a table T2 that would return the length as if the  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={     ={},     ={},     ={}, }   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  key returning a size? ipairs() will not traverse them, but (for i=1, #table) will? This should not be.
Reply | Threaded
Open this post in threaded view
|

## Re: Possible bug relating to table sizes

 > assert(#T1 == #T2)  -- will fail You cannot compare tables like that. Two variables containing a table will be equal only if they are in fact pointing to the same table, not if the table has the same contents. (Unless you changed the behavior with metatables) > ---------------------------------------- > T1={} > for i = 2, 4 do >     T1[i] = {} > end > print(#T1) > ---------------------------------------- # is not biuniquely defined for non linear tables that do not go from 1...n.  You can read up the exact definition of #, but usually just don't do it for something that is not defined 1..n. > > 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  key returning a size? ipairs() will not traverse them, but (for i=1, #table) will? This should not be. Read it up in the Lua manual. "The length operator is denoted by the unary operator #. The length of a string is its number of bytes (that is, the usual meaning of string length when each character is one byte). 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 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 the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array)"
Reply | Threaded
Open this post in threaded view
|

## Re: Possible bug relating to table sizes

 2011/10/29 Axel Kittenberger <[hidden email]>: > # is not biuniquely defined for non linear tables that do not go from > 1...n.  You can read up the exact definition of #, but usually just > don't do it for something that is not defined 1..n. > … > 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 is nil, n can be > zero. Lua 5.2 beta pitches it more strongly: # is _undefined_ for tables that do not go from 1...n, unless you have defined a __len metamethod.  So that last sentence is no longer valid. Dirk
Reply | Threaded
Open this post in threaded view
|

## Re: Possible bug relating to table sizes

 In reply to this post by Axel Kittenberger Whoa, looks like the crazy size operator is still claiming victims :) On Sat, Oct 29, 2011 at 11:22 AM, Axel Kittenberger <[hidden email]> wrote: >> assert(#T1 == #T2)  -- will fail > > You cannot compare tables like that. Two variables containing a table > will be equal only if they are in fact pointing to the same table, not > if the table has the same contents. (Unless you changed the behavior > with metatables) Not to be nitpicking, but: He compares the sizes here, not the tables themselves (note the # operator). Stefan