Web Analytics

Inheritance in Lua

Intermediate ~30 min read

Inheritance allows you to create new classes based on existing ones, reusing and extending functionality. In Lua, inheritance is implemented using metatables and the __index metamethod. You can create class hierarchies, override methods, and implement polymorphism. Let's explore how to build powerful inheritance systems in Lua!

Basic Inheritance

Create a child class that inherits from a parent class:

-- Parent class
local Animal = {}
Animal.__index = Animal

function Animal:new(name)
    local self = setmetatable({}, Animal)
    self.name = name
    return self
end

function Animal:speak()
    print(self.name .. " makes a sound")
end

-- Child class
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog

function Dog:new(name, breed)
    local self = setmetatable({}, Dog)
    self.name = name
    self.breed = breed
    return self
end

function Dog:speak()
    print(self.name .. " barks: Woof!")
end

local animal = Animal:new("Generic Animal")
local dog = Dog:new("Buddy", "Golden Retriever")

animal:speak()  -- Generic Animal makes a sound
dog:speak()     -- Buddy barks: Woof!
How it works:
  1. Dog has Animal as its metatable
  2. When a method isn't found in Dog, Lua looks in Animal
  3. This creates an inheritance chain: Dog โ†’ Animal
Output
Click Run to execute your code

Calling Parent Methods (Super)

Access parent class methods from child class:

local Animal = {}
Animal.__index = Animal

function Animal:new(name)
    local self = setmetatable({}, Animal)
    self.name = name
    self.energy = 100
    return self
end

function Animal:eat()
    self.energy = self.energy + 10
    print(self.name .. " is eating")
end

-- Child class
local Dog = setmetatable({}, {__index = Animal})
Dog.__index = Dog

function Dog:new(name, breed)
    -- Call parent constructor
    local self = Animal.new(self, name)
    setmetatable(self, Dog)
    self.breed = breed
    return self
end

function Dog:eat()
    -- Call parent method
    Animal.eat(self)
    print("Energy is now: " .. self.energy)
end

local dog = Dog:new("Buddy", "Golden Retriever")
dog:eat()
-- Buddy is eating
-- Energy is now: 110
Output
Click Run to execute your code

Multiple Levels of Inheritance

Create deep inheritance hierarchies:

-- Base class
local Shape = {}
Shape.__index = Shape

function Shape:new()
    local self = setmetatable({}, Shape)
    return self
end

function Shape:getArea()
    return 0
end

-- Rectangle inherits from Shape
local Rectangle = setmetatable({}, {__index = Shape})
Rectangle.__index = Rectangle

function Rectangle:new(width, height)
    local self = setmetatable({}, Rectangle)
    self.width = width
    self.height = height
    return self
end

function Rectangle:getArea()
    return self.width * self.height
end

-- Square inherits from Rectangle
local Square = setmetatable({}, {__index = Rectangle})
Square.__index = Square

function Square:new(side)
    local self = Rectangle.new(self, side, side)
    setmetatable(self, Square)
    return self
end

local square = Square:new(5)
print(square:getArea())  -- 25

Polymorphism

Different objects respond to the same method call in their own way:

local Shape = {}
Shape.__index = Shape

function Shape:new()
    return setmetatable({}, Shape)
end

function Shape:draw()
    print("Drawing a shape")
end

-- Circle
local Circle = setmetatable({}, {__index = Shape})
Circle.__index = Circle

function Circle:new(radius)
    local self = setmetatable({}, Circle)
    self.radius = radius
    return self
end

function Circle:draw()
    print("Drawing a circle with radius " .. self.radius)
end

-- Rectangle
local Rectangle = setmetatable({}, {__index = Shape})
Rectangle.__index = Rectangle

function Rectangle:new(width, height)
    local self = setmetatable({}, Rectangle)
    self.width = width
    self.height = height
    return self
end

function Rectangle:draw()
    print("Drawing a rectangle " .. self.width .. "x" .. self.height)
end

-- Polymorphism in action
local shapes = {
    Circle:new(5),
    Rectangle:new(10, 20),
    Circle:new(3)
}

for i, shape in ipairs(shapes) do
    shape:draw()  -- Each shape draws itself differently
end
Output
Click Run to execute your code

Inheritance Helper Function

Create a reusable function to simplify inheritance:

local function class(base)
    local c = {}
    
    if base then
        setmetatable(c, {__index = base})
    end
    
    c.__index = c
    
    function c:new(...)
        local instance = setmetatable({}, c)
        if instance.init then
            instance:init(...)
        end
        return instance
    end
    
    return c
end

-- Usage
local Animal = class()

function Animal:init(name)
    self.name = name
end

function Animal:speak()
    print(self.name .. " makes a sound")
end

-- Dog inherits from Animal
local Dog = class(Animal)

function Dog:init(name, breed)
    Animal.init(self, name)
    self.breed = breed
end

function Dog:speak()
    print(self.name .. " barks!")
end

local dog = Dog:new("Buddy", "Golden Retriever")
dog:speak()  -- Buddy barks!

Practical Examples

Employee Hierarchy

-- Base Employee class
local Employee = {}
Employee.__index = Employee

function Employee:new(name, salary)
    local self = setmetatable({}, Employee)
    self.name = name
    self.salary = salary
    return self
end

function Employee:getInfo()
    return self.name .. " - $" .. self.salary
end

function Employee:getBonus()
    return self.salary * 0.1  -- 10% bonus
end

-- Manager inherits from Employee
local Manager = setmetatable({}, {__index = Employee})
Manager.__index = Manager

function Manager:new(name, salary, department)
    local self = Employee.new(self, name, salary)
    setmetatable(self, Manager)
    self.department = department
    return self
end

function Manager:getBonus()
    return self.salary * 0.2  -- 20% bonus for managers
end

function Manager:getInfo()
    return Employee.getInfo(self) .. " (Manager of " .. self.department .. ")"
end

local emp = Employee:new("Alice", 50000)
local mgr = Manager:new("Bob", 80000, "Engineering")

print(emp:getInfo())  -- Alice - $50000
print(emp:getBonus())  -- 5000

print(mgr:getInfo())  -- Bob - $80000 (Manager of Engineering)
print(mgr:getBonus())  -- 16000

Vehicle Hierarchy

local Vehicle = {}
Vehicle.__index = Vehicle

function Vehicle:new(brand, model)
    local self = setmetatable({}, Vehicle)
    self.brand = brand
    self.model = model
    self.speed = 0
    return self
end

function Vehicle:accelerate(amount)
    self.speed = self.speed + amount
end

function Vehicle:getInfo()
    return self.brand .. " " .. self.model .. " - Speed: " .. self.speed
end

-- Car inherits from Vehicle
local Car = setmetatable({}, {__index = Vehicle})
Car.__index = Car

function Car:new(brand, model, doors)
    local self = Vehicle.new(self, brand, model)
    setmetatable(self, Car)
    self.doors = doors
    return self
end

function Car:honk()
    print("Beep beep!")
end

-- Motorcycle inherits from Vehicle
local Motorcycle = setmetatable({}, {__index = Vehicle})
Motorcycle.__index = Motorcycle

function Motorcycle:new(brand, model, hasWindshield)
    local self = Vehicle.new(self, brand, model)
    setmetatable(self, Motorcycle)
    self.hasWindshield = hasWindshield
    return self
end

function Motorcycle:wheelie()
    print("Doing a wheelie!")
end

local car = Car:new("Toyota", "Camry", 4)
local bike = Motorcycle:new("Harley", "Davidson", true)

car:accelerate(60)
car:honk()
print(car:getInfo())

bike:accelerate(80)
bike:wheelie()
print(bike:getInfo())
Output
Click Run to execute your code

Practice Exercise

Try these inheritance challenges:

Output
Click Run to execute your code

Summary

In this lesson, you learned:

  • Creating inheritance using metatables and __index
  • Calling parent methods (super) from child classes
  • Building multiple levels of inheritance
  • Implementing polymorphism for flexible code
  • Creating inheritance helper functions
  • Practical examples: Employee and Vehicle hierarchies

What's Next?

You've mastered inheritance in Lua! Next, we'll explore modulesโ€”how to organize your code into reusable packages, manage dependencies, and create clean APIs. Let's continue! ๐Ÿš€