In this section, we will apply the information from the last two sections into an actual example. Let’s implement a Car class in which we will make Car objects. Cars have a state (like their color or speed) as well as behavior like accelerating or honking the horn. We will create fields and methods for both of these.
We start by defining a car metatable and a table of car methods. We set the __index metamethod so when a new car object is given this metatable, we can access our methods through it.
-- The metatable for future car objects
local CarMetatable = {}
-- The table of car methods (functions)
local CarMethods = {}
-- Set the __index metamethod of the metatable
-- so that we can access the car methods through
-- car objects.
CarMetatable.__index = CarMethods
Next, we write a function to create a new car of a certain color and set the metatable properly. Additionally, we can initialize the speed field to zero. A function like this is called a constructor.
function newCar(color)
local car = {}
car.color = color
car.speed = 0
setmetatable(car, CarMetatable)
return car
end
Excellent, now write some methods for the car, like acceleration and honking the horn. Store these in the CarMethods table. Remember that we’re going to call these methods with colon syntax, so the first argument is going to be the car we’re working with. Let’s call this first parameter self .
CarMethods.honk = function (self)
print("Beep beep!")
end
An important thing to mention here is that the following function definitions are all equivalent:
-- A good way to define a method
CarMethods.accelerate = function (self)
self.speed = self.speed + 20
end
-- A better way to define a method
function CarMethods.accelerate(self)
self.speed = self.speed + 20
end
-- The cleanest way to define a method
function CarMethods:accelerate()
self.speed = self.speed + 20
end
For the last one, we are defining the function with a colon! This tells Lua that we’re going to implicitly create a local variable called self which refers to the first argument to the function. Conveniently, when we call the method with the colon syntax, self is automatically filled with the car in question.
And this is all we need to have something workable. Create a new car with the newCar function and use some of its methods (don’t forget to use a colon instead of a period)!
local ferrari = newCar("red")
ferrari:honk()
ferrari:accelerate()
print("My Ferrari is going " .. ferrari.speed .. " miles per hour")
In the next article, we’ll talk about ways to clean up this code more.