Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Checking errors for adding tables with __add metamethod?

Asked by
funyun 958 Moderation Voter
9 years ago

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

Log in to vote
5
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago

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!

Ad

Answer this question