Determining the Length of Lua Lists

Lua includes a length operator # which (in theory) returns the number of items contained in the value to which it is applied. However, it is frankly a bit wonky and can give unexpected results if used outside of a fairly narrow range of applications. Let's take a look:

We learned earlier than tables are collections of values. It can often be helpful to know how many values are contained in a collection. Let's look a list-like tables first:

Lists

Let's create a list then see how many items are in it:

local x = { 1, 2, 3, 5, 6 }

print(#x) -- 5

Ok, that worked as we might expect. Five values we added to the list, and the length operator returned a length of 5. Let's see what happens with a list of nil values:

local y = { nil, nil }

print(#y) -- 0

Hmm, the list contains 2 nil values, but returns a length of 0. Should we have expected a length of 0 or a length of 2? On one hand there are 2 nil values in the list, but on the other hand nil is considered to be "not a value".

Let's leave that debate to the philosophers, the important thing for programmers is that Lua has an opinion about this, and applies that opinion consistently. So, based on this result we can conclude that Lua does not count nil values in lists.

Let's look at another example:

local x = { 1, 2, 3, nil, 4, 5 }

print(#x) -- 6

Er, hold on. Lua counted nil as a value this time?

It turns out that the process Lua uses to calculate the length of list-like tables is not as simple as counting values in the list, and gets complicated when the list contains nil values. Even worse, the result that is returned depends not only on the values that are in the list at the time that the length operator is applied, it depends on how the table was created and populated. Let's see what happens when we build this table another way:

local y = {}
y[1] = 1
y[2] = 2
y[3] = 3
y[4] = nil
y[5] = 4
y[6] = 5

print(#y) -- 3

Although these tables contain the same values, this table has a length of 3? After digging through the Lua documentation to gain a better understanding of how this operator works, we have learned that the situation is even worse than expected - this example could have returned any of 2, 3, 5, or 6.

So, while the length operator can be useful with list-like tables, care must be taken to ensure that the lists it operates don't contain any nil values.