Just moments ago I wasted about 30 mins trying to figure out an error in a big script I’m working on. I thought the error was a typo or an incorrect variable, turns out it came from a simple if statement going the unintended path.
I cannot understand why checking if a table == table returns false, I’m not an experienced scripter or a genius but I’m pretty sure this should be true and otherwise breaks the logic I’ve learned throughout programming.
Am I just dumb or is this an intended feature???
local a = {}
if a == {} then
print(“yay let’s do stuff now”)
else
print(“how did we get here???”)
end
I remember from somewhere it is its hash or related to memory or something, those 2 items have different internal “memory addresses”
(I dont know the exact terms but i tried to make it as simple as possible)
{} is the table literal constructor, every time you use it a new table is created. On the other hand the equality, ==, for tables in Lua works as follows: it returns true only when both sides of the equality are the same table. When you do {} == {}, you are saying: “a new table is equal to another new table” which is false. To get true you would have to do:
local tab = {}
print(tab == tab) -- "table tab is equal to table tab?" -> true
for your example, a == {} , “table a is equal to a new table?” → false
local a = {}
if next(a) == nil then
print("yay let's do stuff now")
else
print("how did we get here???")
end
But if both your tables have values and you want to see if they are the same, you can compare with a function such as:
local function tableMatch(tbl1, tbl2)
if type(tbl1) ~= 'table' then return false end
if type(tbl2) ~= 'table' then return false end
for index, v in pairs(tbl1) do
if v ~= tbl2[index] then return false end
end
for index, v in pairs(tbl2) do
if v ~= tbl1[index] then return false end
end
return true
end
which you could just do if tableMatch(table1, table2) then print(“”) end
In simple terms, tables in Lua - unlike other types of variables - are passed by reference. The idea is difficult to explain, so let’s consider a different concept first:
-- example 1
local a = 5
local b = a
b = b + 1
print(a)
-- example 2
local c = {}
local d = c
table.insert(d, 1)
print(#c)
Intuitively you would expect the first print to output 5 and the second print to output 0. However, what is actually printed is this:
5
1
This may be confusing, but in the first example variables are passed by value. This is almost always what happens when you set a variable to some value. A copy of the value is made and then stored inside the new variable.
Tables however, are passed by reference. When you use local d = c, what happens is that the location of where the table is stored in your hardware’s memory is copied over to d. So variables c and d are both the same tables. Making a change to one of them will also change the other.
This concept extends to comparing tables as well:
local x = {}
local y = x
local z = {}
print(x == y)
print(y == z)
This will print:
true
false
This is because table comparisons in Lua are done by checking if both tables are pointing to the same location in your memory. In the first print, x and y are both pointing to the same table, so it returns true. In the second print however, y and z are different tables (despite both being tables with the same content inside of them). But because they are stored at a different location, they are not the same, so the print statement outputs ‘false’.
How tables (or arrays, in most other programming languages) are compared is different per language, but in the case of Lua, this is how it works.
Whenever you do {} it allocates a new table. Tables are equal only if they are the exact same table, so creating two and comparing them like this will never be true. That is, the == operator on tables is not a set equality check. You could make a table whose == operator does do that though, by checking that the other table contains the exact same elements.
I actually figured out this pattern a long time ago and whenever I needed to transfer all items from one table to another, I’d use a for loop to get around this reference issue.
I never knew exactly why it happened but now I know thank you!