Classes in Lua

Use metatables and metamethods to bring object-oriented features to Lua.

by megabean99

Author Avatar

This tutorial will teach you how to make classes in Lua. Lua does not have classes, but it has metatables and metamethods. We can use those to make a sort of pseudo-class.

What's a class?

If you didn't already know, a class is a staple feature of object-oriented programming. They allow us to define objects, with special values and attributes. Take this Java code for example:

class Pie() {
    public String flavor;
    public int slices;
    Pie(String f, int s) {
        flavor = f;
        slices = s;
    }
    public void printData() {
        System.out.println("Pie flavor: " + flavor);
        System.out.println("Slices remaining: " + Integer.toString(slices));
    }
}

Looks complicated, right? Don't worry if you don't know what it means! At the very core, it defines a class named Pie which has several attributes, such as a flavor and how many slices of it are left. It has a method called printData which prints out the amount of slices left of the pie and the flavor. Every pie created will have its own unique flavor and slice count.

Now, let's make our own pie in Lua.

But how are we going to do it? As previously stated, Lua doesn't have classes. How can we make something similar to this?

The answer to this question involves two things: metatables and metamethods. Metatables are effectively tables within tables, which have to be created manually. Metamethods are special properties or functions that a table can have within it.

Let's define a class named Pie, and set its __index metamethod:

local Pie = {}
Pie.__index = Pie

Easy enough so far. But what does "__index" mean?

To answer that, let's skip a few steps. Say our class is complete and we can create a new instance of it with the function:

Pie.new()

This "new" function is called a constructor. They execute code and take values from the arguments in it to modify or save for later use.

Say I put some arguments into that new function; A flavor for the pie, and the amount of slices it has.

local MyPie = Pie.new("Blueberry", 5)

Let's say I had a different pie, but forgot to put how many slices it has. The __index keyword tells the new() function to use the table and the missing argument as the argument. It's a bit complicated to understand, you can learn more by reading "Programming in Lua" or going to lua.org.

Anyways, let's continue with our code for our Pie class.

Let's define our constructor function:

function Pie:new(flavor, slices)
    local pie1 = {}
    setmetatable(pie1, Pie)
    pie1.flavor = flavor
    pie1.slices = slices
    return pie1
end

This creates a new empty "dummy" table which is returned after creating a new Pie. It sets its flavor and slices values to the ones provided. Now that we have our constructor function, we can define a function for our Pie class. Let's use the printData one from the Java example:

function Pie:PrintData()
    print("Pie flavor: ", self.flavor)
    print("Slices remaining: ", tostring(self.slices))
end

We can now create a new instance of Pie and print its data:

local pie1 = Pie:new("Apple", 7)
pie1:PrintData()
--[[
expected output:
Pie flavor: Apple
Slices remaining: 7
]]--

Congratulations, you just made a class in Lua! I hope this helps you manage objects easier in your game development journey!

Complete code:

local Pie = {}
Pie.__index = Pie

function Pie:new(flavor, slices)
    local pie1 = {}
    setmetatable(pie1, Pie)
    pie1.flavor = flavor
    pie1.slices = slices
    return pie1
end

function Pie:PrintData()
    print("Pie flavor: ", self.flavor)
    print("Slices remaining: ", tostring(self.slices))
end