Lua DISCUSSION

Why does the # length operator give unexpected results on a Lua table containing nil?

Started by arunkumarannamalai Lua length operatortable with holessequence bordercounting table entriesipairs
5 replies 248 views 6 participants
Latest activity · 30 Sep 2026

Why does the # length operator give unexpected results on a Lua table containing nil?

arunkumarannamalai Lua Forum
#1

I store ADC samples in a Lua table and mark failed readings by assigning nil to that position. After that, #samples sometimes returns the full count and sometimes a smaller number, and my for i = 1, #samples loop stops early. A second table that uses string keys always reports a length of 0.

How is the length of a table actually defined, and what is the correct way to count the entries?

Community replies 5

Re: Why does the # length operator give unexpected results on a Lua table containing nil?

#2

#t is only well defined for a sequence: a table whose positive integer keys run from 1 to n with no gaps. For any other table the operator may return any border, meaning any index n where t[n] is not nil and t[n + 1] is nil (or 0 when t[1] is nil). With {10, 20, nil, 40} both 2 and 4 are borders, so both are valid results, and which one you get depends on how the table was built and on its internal layout. That is why the result seems to change.

Re: Why does the # length operator give unexpected results on a Lua table containing nil?

#3

The length operator never looks at non-integer keys. A table such as {pin = 4, mode = "adc"} has no element at index 1, so its length is 0 even though it holds two entries. To count every key you have to walk the table: local n = 0; for _ in pairs(t) do n = n + 1 end. That is O(n) each time, so if the count is needed often, keep your own counter and update it wherever you insert or remove.

To test for an empty table, next(t) == nil is enough and does not iterate.

Re: Why does the # length operator give unexpected results on a Lua table containing nil?

#4

For the samples, do not put nil inside the array. Store a placeholder that cannot be a real reading, for example false or -1, and test for it when processing. false is a real value, so it does not make a hole and #samples stays correct.

If you need real nils, keep the count explicitly in a field, the way table.pack(...) does with its n field, and loop with for i = 1, samples.n do.

Re: Why does the # length operator give unexpected results on a Lua table containing nil?

#5

Assigning nil is also how entries are deleted, so t[k] = nil in the middle of an array does not shift anything down; it leaves a gap. Use table.remove(t, i) when later elements must move up, keeping in mind that it shifts everything after i and so costs O(n). Appending is t[#t + 1] = v or table.insert(t, v); both rely on the table being a proper sequence.

For the same reason ipairs stops at the first nil, while pairs visits every key but in no guaranteed order.

Re: Why does the # length operator give unexpected results on a Lua table containing nil?

#6

On the cost side: #t is not a stored field. The reference implementation searches for a border, using a binary search when it has to, so it is cheap but not free. If a loop body needs the length repeatedly, read it once into a local with local n = #t.

The numeric for evaluates its limit only once, so for i = 1, #t do is fine as written. It also means the loop does not notice elements appended while it runs, which is worth knowing if the body adds to the same table.

TEP COMMUNITY