Overriding Methods
Part of the Object Oriented Programming section of Coddy's Lua journey — lesson 37 of 70.
So far, child classes have inherited parent methods and added new ones. But what if a child needs the same method name with different behavior? This is called method overriding.
When you define a method in a child class with the same name as one in the parent, the child's version takes priority. Lua's lookup chain checks the child class first—if it finds the method there, it stops looking.
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog overrides speak()
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
print(self.name .. " barks: Woof!")
endNow each class responds differently to the same method call:
local generic = Animal:new("Creature")
local buddy = Dog:new("Buddy")
generic:speak() -- Output: Creature makes a sound
buddy:speak() -- Output: Buddy barks: Woof!The Dog's :speak() completely replaces the parent's version for Dog instances. This lets you create specialized behavior while keeping a consistent interface—every animal can :speak(), but each species does it differently.
Challenge
EasyLet's build a small animal kingdom where different creatures speak in their own unique ways! You'll create a Animal parent class and two child classes—Cat and Cow—that each override the parent's :speak() method with their own specialized behavior.
You'll organize your code across four files:
Animal.lua: Your base class with a:new(name)constructor that stores the animal's name. Include a:speak()method that prints the animal's name followed bymakes a sound. This is the default behavior that child classes will override.Cat.lua: A child class that inherits from Animal. Its:new(name)constructor should call the parent constructor, then re-link the metatable to Cat. Override the:speak()method so that cats say something different—print the cat's name followed bymeows: Meow!Cow.lua: Another child class inheriting from Animal. Set up the constructor the same way as Cat. Override:speak()so that cows print their name followed bymoos: Moo!main.lua: Bring everything together! Read two names from input, create a Cat with the first name and a Cow with the second name, then call:speak()on each to demonstrate that the same method name produces different output depending on the class.
You will receive two inputs:
- The cat's name
- The cow's name
In your main file, create both animals and call :speak() on the cat first, then on the cow.
For example, if the inputs are Whiskers and Bessie, the output should be:
Whiskers meows: Meow!
Bessie moos: Moo!Notice how both animals respond to the same :speak() method call, but each produces output specific to its type. The Cat's version completely replaces the parent's generic "makes a sound" behavior, and so does the Cow's. This is method overriding in action—same interface, different implementations!
Cheat sheet
Method overriding allows a child class to define a method with the same name as a parent method, replacing the parent's behavior with specialized functionality.
When Lua looks up a method, it checks the child class first. If it finds the method there, it uses that version and stops searching the parent class.
Basic example of method overriding:
local Animal = {}
Animal.__index = Animal
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
function Animal:speak()
print(self.name .. " makes a sound")
end
-- Dog overrides speak()
local Dog = {}
Dog.__index = Dog
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
end
function Dog:speak()
print(self.name .. " barks: Woof!")
endUsing the overridden method:
local generic = Animal:new("Creature")
local buddy = Dog:new("Buddy")
generic:speak() -- Output: Creature makes a sound
buddy:speak() -- Output: Buddy barks: Woof!The child class's method completely replaces the parent's version for instances of that child class, allowing specialized behavior while maintaining a consistent interface across all classes.
Try it yourself
-- main.lua: Bring everything together
local Cat = require('Cat')
local Cow = require('Cow')
-- Read input
local catName = io.read()
local cowName = io.read()
-- TODO: Create a Cat with the first name
-- TODO: Create a Cow with the second name
-- TODO: Call :speak() on the cat first, then on the cow
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1The 'Self' Concept
Tables with FunctionsExplicit 'self'The Colon SyntaxDot vs ColonRecap - Moving Point4Project: Digital Bank
Project SetupDeposit Method7Polymorphism & Overriding
Overriding MethodsCalling Parent MethodsDuck TypingCommon InterfaceChecking TypeRecap - Employee Roles10Project: Shape Manager
Project SetupRectangle Class2Class Prototype Pattern
The Prototype ConceptLinking with __indexThe :new() ConstructorInitializing AttributesIndependent InstancesRecap - Car Factory5Operator Overloading in OOP
Adding ObjectsSubtracting ObjectsConcatenating ObjectsComparing Objects (<, >)Recap - Wallet Math8Encapsulation
Naming ConventionsClosures for PrivacyAccess via ClosuresRead-Only TablesValidation LogicRecap - Secure Vault11Design Patterns (Lite)
Factory FunctionsSingleton TableIterator PatternObserver (Listener)Recap - Logger Factory3Object State and Behavior
Instance VariablesGetter MethodsSetter MethodsCalculated PropertiesFormatting StringsEquality ChecksRecap - Student Grade6Inheritance Basics
The Inheritance SetupInheriting MethodsExtending the ConstructorAdding Child MethodsShared vs UniqueRecap - Shape Hierarchy