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.