🎓 A1Learner
🔍
0 of 52 lessons completed

Lua Polymorphism

Polymorphism is a way to call the same method name on different kinds of objects, with each kind doing its own version.

Different classes can share one method name

Dog and Cat both define speak. Each object uses its own class version.

local Dog = {}
Dog.__index = Dog
function Dog.new(name)
  local self = setmetatable({}, Dog)
  self.name = name
  return self
end
function Dog:speak()
  return self.name .. " says Woof"
end
local Cat = {}
Cat.__index = Cat
function Cat.new(name)
  local self = setmetatable({}, Cat)
  self.name = name
  return self
end
function Cat:speak()
  return self.name .. " says Meow"
end
local d = Dog.new("Rex")
local c = Cat.new("Milo")
print(d:speak())
print(c:speak())

One loop calls the same method on mixed objects

A list holds a dog and a cat. The loop calls speak on each object in turn, and each object answers in its own way.

local Dog = {}
Dog.__index = Dog
function Dog.new(name)
  local self = setmetatable({}, Dog)
  self.name = name
  return self
end
function Dog:speak()
  return self.name .. " says Woof"
end
local Cat = {}
Cat.__index = Cat
function Cat.new(name)
  local self = setmetatable({}, Cat)
  self.name = name
  return self
end
function Cat:speak()
  return self.name .. " says Meow"
end
local animals = {Dog.new("Rex"), Cat.new("Milo")}
for _, animal in ipairs(animals) do
  print(animal:speak())
end

A helper can call the method without knowing the kind

The makeSound helper takes any animal and calls speak on it. It works for a dog and for a cat without a class check.

local Dog = {}
Dog.__index = Dog
function Dog.new(name)
  local self = setmetatable({}, Dog)
  self.name = name
  return self
end
function Dog:speak()
  return self.name .. " says Woof"
end
local Cat = {}
Cat.__index = Cat
function Cat.new(name)
  local self = setmetatable({}, Cat)
  self.name = name
  return self
end
function Cat:speak()
  return self.name .. " says Meow"
end
local function makeSound(animal)
  return animal:speak()
end
local d = Dog.new("Rex")
local c = Cat.new("Milo")
print(makeSound(d))
print(makeSound(c))

Example

local Dog = {}
Dog.__index = Dog
function Dog.new(name)
  local self = setmetatable({}, Dog)
  self.name = name
  return self
end
function Dog:speak()
  return self.name .. " says Woof"
end
local Cat = {}
Cat.__index = Cat
function Cat.new(name)
  local self = setmetatable({}, Cat)
  self.name = name
  return self
end
function Cat:speak()
  return self.name .. " says Meow"
end
local Duck = {}
Duck.__index = Duck
function Duck.new(name)
  local self = setmetatable({}, Duck)
  self.name = name
  return self
end
function Duck:speak()
  return self.name .. " says Quack"
end
local animals = {Dog.new("Rex"), Cat.new("Milo"), Duck.new("Daisy")}
for _, animal in ipairs(animals) do
  print(animal:speak())
end

Key points

  • Shared method name: Different classes can define a method with the same name, such as speak.
  • Own version: Each class version runs for objects of that class.
  • Mixed list: One list can hold objects of different classes, and one loop can call the same method on each object in turn.
  • No class check: The loop does not need to check each object class before calling the method.
  • New kind: A new class with the same method name works in the same loop without changing the loop.

In this example, Dog, Cat, and Duck each define a speak method with their own sound. A list holds one object of each kind. A loop calls speak on each object in turn, and each object answers with its own sound.

Note

Lua finds the right version at call time through the object metatable, so the caller does not choose the version.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A loop calls speak on a list holding a dog, a cat, and a duck. What happens?