Menu
Coddy logo textTech

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!")
end

Now 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 icon

Challenge

Easy

Let'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 by makes 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 by meows: 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 by moos: 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:

  1. The cat's name
  2. 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!")
end

Using 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
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming