This guide assumes you are already familiar with the basics of Lua, including tables, strings, the number type, and functions. Here are a few things you can do to avoid common and/or hard-to-debug mistakes in Lua.
*or on a table where the metafunction
- Do not compare tables with
==
.
Ex:
Lua:--Do not do this! {a = 5} == {a = 5} --=> false
false
! When comparing tables, lua uses what's called reference equality, which means that it will only returntrue
if both sides are the same table, not just the same properties with the same values.
Lua:local tableA = {a = 5} local tableB = tableA local tableC = {a = 5} tableA == tableB --=> true tableA == tableC --=> false tableA.a == tableC.a --=> true
- Do not use
#
on anything except an "array-like" table or a string*.
Lua:local coolString = "abc123" local arrayLike = {10, 20, 30, 40} local alsoArrayLike = { a = 5, [1] = 10, [2] = 20, [3] = 30 } local notArrayLike = {10, 20, nil, 40} #coolString --=> 6 #arrayLike --=> 4 #alsoArrayLike --=> 3 #notArrayLike --=> undefined behavior! Avoid at all costs!
"array-like" in this case means that there are no "holes" in the numbers; Either no number rows are defined or every number row up to the maximum has a value that isn'tnil
. This is also refered to as a "sequence" in the docs.
If you invoke#
on a table with holes in it, the result is undefined behavior! Undefined behavior means that the Lua interpreter can do whatever it wants. It can return0
,100
,nil
, it can abort, explode, set the array to the lyrics of the bee movie, anything. Anytime you hear the words undefined behavior, run in the opposite direciton and avoid at all costs. Act as if every time you invoke undefined behavior, millions of poisonous spiders are going to crawl out of your keyboard and eat you alive.
Note that while you can use#
on a table with non-numeric keys as long as any numeric keys are array-like, I wouldn't reccomend it simply because the behavior (only counting the numeric keys) can be confusing.
If you need to count how many rows a table has, you have to do it like this:
Lua:local tableToCount = { a = 1, [3] = "abc", x = {1,2,3} } local count = 0 for _,_ in pairs(tableToCount) do count = count + 1 end count --=> 3
- Do not compare decimal numbers.
Lua:0.3 - 0.2 --=> print will tell you "0.1", but it's actually 0.09999999999999998 (0.3 - 0.2) == 0.1 --=> false
print
. This usually doesn't matter, as they're more than precise enough for most calculations, but if you try to compare them you may get unexpected results.
If you really need to compare decimal numbers, you use what's called an epsilon, which is a very small number that you've decided, if two numbers are within epsilon of eachother, they're "close enough".
Lua:local function compareDecimals(a, b, epsilon) return math.abs(a - b) < epsilon end local epsilon = 0.0001 compareDecimals(0.3 - 0.2, 0.1, epsilon) --=> true
If you're only comparing integer numbers, you don't need to worry about this unless... - Make sure your integers don't go above 2^53 or below -2^53
Lua:local function returnZero(a) --silly function, but it should always return 0, right? local b = a + 1 local c = b - a return c - 1 end returnZero(5) --=> 0 returnZero(100) --=> 0 returnZero(-43893) --=> 0 --so far so good... returnZero(2^53) --=> -1 --oh noes!
Fortunately you won't need to worry about running out of precision for array indexes; An array with 2^53 elements would take up over 9 petabytes of RAM. That's 9 million gigabytes.
*or on a table where the metafunction
__len
is defined and you're using lua 5.2, see Lua reference manual 3.4.6