Why is {}=={} (table == table) equal to false?

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
3 Likes

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)

5 Likes

{} 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

6 Likes

what you could do to check if it is empty is:

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

4 Likes

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.

10 Likes

For tables LUA checks if they are equal by checking their memory address (reference), not the value how it does for every other struct.

2 Likes

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.

3 Likes

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!

2 Likes

I ended up using a different if statement as i posted this question after I solved my issue.

But I also learned how to use the next() function and this is helpful for the future, thanks!

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.