Easy Inheritance & Modularity in Lua

Seeing many flash developers praising Lua-based SDKs like Corona and Gideros that allow us to create mobile games quickly, I couldn’t help trying them myself.

First thing I did was read up some Lua tutorials. The language seems pretty easy to grasp — everything is a table which looks like associative array or a Dictionary in AS3. Good. Until I got to the point where I want to apply/emulate OOP or write code in modular fashion. This is where things become confusing because code examples from Corona and Gideros show you how to shove everything in one big main.lua file. To add even more confusion, different Lua OOP examples show you how to emulate OOP in different ways. And there are things called metatable and metamethods.

After an hour reading the docs and wiki and doing some experiments. I found that it’s really not that hard. Here’s an example of inheritance in one big file.

-------------------
-- Car table/class
-------------------
Car = {}
Car.__index = Car
--constructor
function Car.new(brand,price)
	local instance = {
		_brand = brand,
		_price = price
	}
	
	-- set Car as prototype for the new instance
	setmetatable(instance, Car)
	return instance
end

-- method definitions
function Car:getBrand()
	return self._brand;
end

function Car:getPrice()
	return self._price;
end

function Car:getInfo()
	print("Brand",self:getBrand(),"price:",self:getPrice())
end

-------------------
-- SUV
-------------------
SUV = {};
-- constructor
SUV.__index = SUV
function SUV.new(brand,price,is4WD)
	local instance = {
		_is4WD = is4WD,
		_price = price,
		_brand = brand,
	}
	-- set SUV as prototype for instance
	setmetatable(instance,SUV)
	return instance
end

-- set up inheritance by making Car as prototype for SUV. Now SUV can access & override Car's methods
setmetatable(SUV,{__index = Car})

-- instance method
function SUV:get4WD()
	return self._is4WD;
end
-- override
function SUV:getInfo()
	print("SUV Brand",self:getBrand(),", price:",self:getPrice(),", 4WD",self:get4WD())
end

-------------------
-- main program
-------------------
local c = Car.new("Honda",100)
c:getInfo();

local suv = SUV.new("Suzuki",150,true)
-- call inherited method
print(suv:getBrand())
-- call the overridden method
print(suv:getInfo())

If you compile and run the program, you should see this in the console:

Brand	Honda price: 100
Suzuki
SUV Brand Suzuki, price: 150, 4WD true

BTW, if you’re on Mac, you should try a cool app called Code Runner. You can do quick experiments without complicated project setup. Just type your code and click run.

Coding in Code Runner

So, how do you separate SUV and Car from main.lua and put them in different .lua files in a package? Easy.

  • Create a directory for your package just like what you always do in AS3, mine is car.
  • Then move Car and SUV definitions from main.lua and put them in SUV.lua and Car.lua respectively.
  • Add return Car at the end of Car.lua & return SUV at the end of SUV.lua.
  • Declare require "car.Car" in SUV.lua to “import” the Car table
  • Import Car and SUV into the main lua

Here’s my directory (package) setup and the code:

Package
-------------------
-- Car table/class
-------------------
Car = {}
Car.__index = Car

--constructor
function Car.new(brand,price)
	local instance = {
		_brand = brand,
		_price = price

	}
	
	-- set Car as prototype for the new instance
	setmetatable(instance, Car)
	return instance
end

-- instance method definitions
function Car:getBrand()
	return self._brand;
end

function Car:getPrice()
	return self._price;
end

function Car:getInfo()
	print("Brand",self:getBrand(),"price:",self:getPrice())
end

-- so that the Car can be imported by other classes via 'require "car.Car"'
return Car
-------------------
-- SUV
-------------------
require "car.Car"

SUV = {};
SUV.__index = SUV

-- constructor
function SUV.new(brand,price,is4WD)
	local instance = {
		_is4WD = is4WD,
		_price = price,
		_brand = brand,
	}
	-- set SUV as prototype for instance
	setmetatable(instance,SUV)
	return instance
end

-- set up inheritance. Now SUV can access & override Car's methods
setmetatable(SUV,{__index = Car})

-- instance methods
function SUV:get4WD()
	return self._is4WD;
end
-- override
function SUV:getInfo()
	print("SUV Brand",self:getBrand(),", price:",self:getPrice(),", 4WD",self:get4WD())
end

-- so that the SUV can be imported by other classes via 'require "car.SUV"'
return SUV;
-- import Car and SUV classes
require "car.Car"
require "car.SUV"

local car = Car.new("Honda",200);
print(car:getInfo())

local suv = SUV.new("Suzuki", 250, true)
-- call inherited method
print(suv:getBrand())
-- call the overridden method
print(suv:getInfo())

Download

Here’s the zip containing the example → inheritance_lua.zip

Also in this category ...