[Quora] What is the call metamethod in Lua?

published 2020-04-09

From 2011 to 2014, I used to post answers on Quora [1]. I don't anymore, because I don't really like what the website has become. I have a copy of some of my answers here [2] but someone commented [3] on one of my answers that it should be available more prominently on the Web, so I decided to repost a few of my answers here, starting with this one.

The original question [4] was:

I'm really new to lua and relatively new to programming.,so kindly excuse if I say something stupid.
I have a table named x and its metatable named y. When I have a __call method defined for the metatable y, then I can call x() but if I have a __call for x then I can not call x().
What is __call used for? How does it work and what are some examples of usage

I answered it on February 25, 2013.

The role of `__call` is to make something that is not a function (usually a table) act like a function. There are a few reasons why you may want to do that. Here are two examples.

The first one is a memoizing factorial function. In Lua you could write a recursive factorial like this:

local function fact(n)

if n == 0 then

    return 1

else

    return n * fact(n - 1)

end

end

Note: this is not a good way to write a recursive factorial because you are not taking advantage of tail calls, but it's enough for what I want to explain.

Now imagine your code uses that function to calculate the factorials of numbers from 1 to `N`. This would be very wasteful since you would calculate the factorial of `N` once, the factorial of `N-1` twice, and so on. You would end up computing approximately `N²/2` factorials.

Instead you could write that:

local fact

fact = setmetatable(

{[0] = 1},

{

    __call = function(t, n)

        if not t[n] then

            t[n] = n * fact(n - 1)

        end

        return t[n]

    end

}

)

It is an implementation of factorial that memoizes the results it has already computed, which you can call like a function. You can use it exactly like the previous implementation of factorial and get linear complexity.

Another use case for `__call` is matrices. Imagine you have a matrix implementation that works like that:

local methods = {

get = function(self, i, j)

    return self[i + 1][j + 1]

end

}

local mt = {__index = methods}

local new_matrix = function(t)

return setmetatable(t, mt)

end

You can use it like that:

local M = new_matrix({ {1, 2}, {3, 4} })

local v = M:get(0, 1)

assert(v == 2)

However scientists would probably expect something like this:

local v = M(0, 1)

assert(v == 2)

You can achieve that thanks to `__call`:

local mt = {

__index = methods,

__call = function(self, i, j)

    return self:get(i, j)

end

}

Proxy Information
Original URL
gemini://separateconcerns.com/2020-04-09-quora-lua-call.gmi
Status Code
Success (20)
Meta
text/gemini;lang=en_US
Capsule Response Time
115.053388 milliseconds
Gemini-to-HTML Time
1.03893 milliseconds

This content has been proxied by September (3851b).