Lua: Methods

From Mario Fan Games Galaxy Wiki
 Standardwikimessagebox.png This page should be syntax highlighted

Code on this page would be more readable and may wrap correctly if it were surrounded by <source> tags using the enclose="div" attribute.

Lua
Lua.gif
Basics
Intermediate
Advanced
XLua
Add to this template
 Standardwikimessagebox.png This article assumes the use of Lua 5.1.

Information may not be accurate or may need revision if you are using a different version.

Methods are functions that are used by an object. 'Object' doesn't necessarily mean a game object, but instead some data structure that contains a set of variables and functions (the methods). Of course, the data structures we will be using are tables (usually).

Lua's methods have a special syntax; you don't need to use this syntax, but it's cleaner and easier than the alternative. Called colon syntax, it of course uses a colon instead of a dot:

-- regular function
table.function_call()

-- method
table:method_call()

Basically, by using the colon, you insert the data structure immediately left of the colon as a hidden first parameter. Therefore, these two calls are equivalent:

table.method(table, other_param)
table:method(other_param)

When you're writing the source code, however, that first parameter will generally be something else. It's just a regular variable, so it doesn't necessarily need to have the same name as the data structure calling the method (you should avoid this, in fact). You'll often see this variable named self, as this is the variable name Lua uses if the method definition does not explicitly state another name for its first parameter.

Table Methods

In order to use methods for any given table, we need to give it a metatable. Because we don't want the methods to actually "pollute" this table, we will have them stored in a separate table called methods. So our code should start out like this:

methods = { }

function newTable(t_data)
    return setmetatable(t_data, methods)
end

Now we need to write a method for the methods table. A useful one will return the length of the entire table, including non-numeric keys, which are normally ignored by the length operator. So our methods table will look like:

methods = {
    length = function (self)
        local l = 0
        for k in pairs(self) do
            if string.sub(k, 1, 2) ~= "__" then
                l = l + 1
            end
        end
        return l
    end,
}
methods.__index = methods

This is a similar table iteration as the __add metamethod from the Metatables tutorial. However, instead of adding the values at two tables' indexes, we're just incrementing a variable to use as our length. Note how we are using string.sub to exclude key names starting with '__'; we don't want metamethods to be counted in the length! We also define methods' __index metamethod to point to itself, so Lua knows this is the table that has the methods we need. We're actually done now, so we should try testing it:

methods = {
    length = function (self)
        local l = 0
        for k in pairs(self) do
            if string.sub(k, 1, 2) ~= "__" then
                l = l + 1
            end
        end
        return l
    end,
}
methods.__index = methods

function newTable(t_data)
    return setmetatable(t_data, methods)
end

test = newTable {1, 2, 3, a = 4, b = 5, c = 6}

print(test:length()) -- prints 6
print(test.length(test)) -- prints 6 (longhand for above)
print(methods.length(test)) -- prints 6 (the "real" call, bypassing the metatable lookup)
print(#test) -- prints 3!
print(newTable {1,2,3, four = 4}:length()) -- believe it or not, this works too (prints 4)

Methods are a nice way to make your code not only cleaner, but also more modular. Instead of having to repeat the same code over and over for multiple tables, you can just __index them to the same methods table and they can all take advantage of methods.