Inheritance in Lua
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!
DoghasAnimalas its metatable- When a method isn't found in
Dog, Lua looks inAnimal - This creates an inheritance chain: Dog โ Animal
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
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
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())
Click Run to execute your code
Practice Exercise
Try these inheritance challenges:
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! ๐
Enjoying these tutorials?