Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Checking errors for adding tables with __add metamethod?

So, I'm trying to learn metamethods. I'm trying to make a script that can add arrays of numbers together, but will error if there's non-number elements in either table. Here's what I have:

t1 = {1, 2, 3}
t2 = {4, 5, 6,"swag noob"}

mt = {
	__add = function(t1, t2)
		for _, v in pairs(t1) do --Check table 1 for non-number values
			if not type(v) == "number" then
				error("Numbers. You need to use numbers!")
				return
			end
		end
		
		for _, v in pairs(t2) do --Same for table 2
			if not type(v) == "number" then
				error("Numbers. You need to use numbers!")
				return
			end
		end
		
		local sumtable = {} --Table of sums
		
		local function add(iterations)
			for i = 1, iterations do
				table.insert(sumtable, t1[i] + t2[i]) --Add elements, put sums in sum table
			end
		end
		
		if #t1 > #t2 then add(#t2) --The next few lines are to make sure that we're not adding elements that don't exist.
		elseif #t1 < #t2 then add(#t1)
		else add(#t1) end
		return sumtable
	end
}

setmetatable(t1, mt)

print(table.concat(t1 + t2, ", "))

Although "swag noob" is not a number value, the output won't error. It will add 1 to 4, 2 to 5, and 3 to 6. That's not what I want. When I take 6 out of the table and leave "swag noob", I get...

Workspace.Script:24: attempt to perform arithmetic on field '?' (a string value)

The errors are supposed to be caught in the beginning of the metamethod, but they aren't.

1 answer

✓ Accepted answer

This is an order-of-operations mistake.

If you check the Lua operator precedence article, you'll see that not is higher precedence than ==. What does that mean?

That means that not a == b is interpretted as (not a) == b -- which is NOT a ~= b.

You should use ~= when you want to see if things are different!


I would suggest a few code-cleanup-things. Repeating code is bad -- you should have a function that checks for non-number values. You can also take advantage of assert to eliminate the if entirely:

function onlyContainsNumber(tab)
	for _, el in pairs(tab) do
		assert(type(el) == "number", "table must contain only numbers")
	end
end

.....
	onlyContainsNumbers(t1)
	onlyContainsNumbers(t2)

I would argue that you usually don't want to add tables of different lengths -- because you'll lose some information, that is probably a mistake when it happens.

Even so, you can simplify your usage of add using math.min, which gives you the smaller of a few numbers (so you can get the shorter of the two lengths)

local sum = {}
for i = 1, math.min(#t1, #t2) do
	sum[i] = t1[i] + t2[i]
	-- Usually `table.insert` describes that you are appending
	-- so it is what you want.
	-- In this case, using `[i] = ` better illustrates the relationship
	-- between sum[i] and t1[i] and t2[i].
	-- (It's also much faster)
end
return sum

You probably want to set the metatable of sum to be mt, too!

This discussion is preserved as it was. New answers, comments, and votes are closed.