Metatable Confusion

So as I’m reading about metatables, and scrolling down I come across a part where you can call functions inside of tables. This is neat, so I get to reading. Okay, but what’s going on here? How does calling ‘t(5)’ return a whole table? What is this script doing?

local metatable = {
	__call = function(t, param)
		local sum = {}
		for i, value in ipairs(t) do
			sum[i] = value + param -- Add the argument (5) to the value, then place it in the new table (t).
		end
		return unpack(sum) -- Return the individual table values
	end
}
 
local t = setmetatable({10, 20, 30}, metatable)
print(t(5)) --> 15 25 35

It’s not returning a table, it’s returning each individual of the element added by 5. unpack as the name implies unpacks a table, by returning each element of it individually.

1 Like

The reason it’s doing that is when you first set up t, you’re giving it a table of information and then setting it to the metatable, which has a function set up to __call, meaning when t he table is called, it will run the function connected to it, and the code in taht function will work because metatables are just tables with special functions/properties. The reason it also prints an entire table is because of

return unpack(sum) -- Return the individual table values

The code in a nutshell is basically doing this

Create a metatable with the table {10,20,30} and give it the metatable variable as the metatable to us

When you call t and specify a number, it will run the function which will make a new variable called sum, and for each value in the table in t, it will add 5 to the value, since you gave it 5 as a number and put it in sum, and then return the result back, which is just the values with 5 added to them in the sum table unpacked into separate values

Excuse me if any of the info is wrong

1 Like

@sjr04 I see that now, my only question is how is the function being called in general? There’s nothing but ‘__call’ in the table, and that isn’t being referenced at all. All that it’s doing is calling t(5), and somehow that’s running the __call function, and adding all those values by 5. How does this make sense?

In regular functions you have to name the functions, and call them by their name. This is not the case, which I don’t understand. What if you had more than 1 __call function inside the table, wouldn’t that be a little difficult to call if you aren’t referencing it properly?

Here is how it works:

t(5)

Argument 5 is evaluated first, since arguments are always evaluated first before the call. Lua(u) then checks if t has a metatable, if it does, invoke the __call metamethod and use its return values.

Lua(u) doesn’t have the concept of named functions, and tables can’t have duplicate keys.

local t = { a = 1 }
t.a = 2
print(t.a) --> 2

it will use the latest assignment, so there is no ambiguity.

Lua is open source. Lua 5.1 source code

1 Like

Firstly, let me just say that these questions aren’t really suited for the devforum. I understand you have questions, and I’ve been there myself, but there are already hundreds of people who have asked the same question and given a better answer than I probably could. Please try to do research to find previous answers instead of creating new threads.

Aside from that, let’s break this down linearly into steps:
First, your code creates table metatable with a function at index __call. Note that __call is a metamethod, so when it is present in a metatable it will be used as a stand-in function when a table with this metatable is called using parentheses, like a function normally would.
Next, your code creates a new table, {10,20,30}, and sets its metatable to be the table you defined above. This means that when you perform actions with or on said table that may trigger a metamethod, lua will try to find specific metamethods in the table’s metatable, this being the metatable table you defined in the first step. (If this needs clarifying, setmetatable returns the first argument passed to it)
After that, you take your table t and attempt to call it with parentheses, similar to how a function would be called. Because you’re not calling a function, you’re actually calling a table, Lua tries to find a specific metamethod in the table t’s metatable that it can use as a stand-in, so that the code can function correctly without errors. Specifically it is looking for a metamethod at the index __call, and it’s expecting the value at that index to be a function. Since we know that table t’s metatable is the table metatable that you defined above, and we can see that there is indeed a function at index __call that Lua will find, it’s clear that lua will use this function instead as it’s stand-in replacement.
Finally, once Lua has found it’s stand-in function at index __call, it attempts to call said function, passing the table you initially attempted to call, t, as the first argument, and the actual arguments you passed in the function call as arguments 2,3, etc. Once the function is finished calling, it will return it’s value, which Lua will forward and use as the return value for your initial call of t. This is why you see 15,20, and 25 as your printed values, because the return values of __call are what the initial call returns to you.

I hope that sufficed as an in-depth explanation, let me know if you have any further questions!