Maybe the 2nd bizarre thing in Lua? (First being array index starts at 1 and not 0)
Per Lua 5.1 Manual
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[1]
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).
Notice the “can be”, which means not necessarily.
And from Lua 5.2 Manual (I don’t think how # works changed between 5.1 and 5.2, just explains it in a different (simpler?) way)
Unless a __len metamethod is given, the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1…n} for some non-negative integer n. In that case, n is its length. Note that a table like
{10, 20, nil, 40}
is not a sequence, because it has the key 4 but does not have the key 3. (So, there is no n such that the set {1…n} is equal to the set of positive numeric keys of that table.) Note, however, that non-numeric keys do not interfere with whether a table is a sequence.
Short answer:
The # operator returns {1…n} , which is only set if the table is a sequence (or a __len metamethod is given). Performing a length check on a table that is not sequenced results in an “unpredictable” value… meaning, the result could be accurate or not, and I read somewhere else that the returned value of said tables can even be 0, -1, or false (not sure which Lua version though).
More insight:
In the examples you provided, removing index 2 using
table.remove(a,2)
assures data stays sequenced as it will shift entries so that there is no nil hole; this is actually the “overhead” sometimes we don’t want and avoid by NOT using table.remove…. but it does come in handy.