Inheritance

An apple tree is a crop too: it grows day by day, and you can describe it like any other crop. But it also has something more: it gives fruit. You could copy the whole Crop class and add to it, but then every change to crops would have to be made twice. Instead, a class can inherit from another class: it gets all of the other class's methods, adds its own, and replaces the ones that should work differently:

local Crop = {}
Crop.__index = Crop

function Crop.new(name, days)
    local crop = {name = name, days = days, age = 0}
    setmetatable(crop, Crop)
    return crop
end

function Crop:grow()
    self.age = self.age + 1
end

function Crop:describe()
    return self.name .. ", day " .. self.age .. " of " .. self.days
end

local Tree = {}
Tree.__index = Tree
setmetatable(Tree, {__index = Crop})

function Tree.new(name, days, fruit)
    local tree = Crop.new(name, days)
    setmetatable(tree, Tree)
    tree.fruit = fruit
    return tree
end

function Tree:describe()
    return Crop.describe(self) .. ", gives " .. self.fruit
end

local wheat = Crop.new("Wheat", 2)
local apple = Tree.new("Apple tree", 30, "apples")
wheat:grow()
apple:grow()
print(wheat:describe())
print(apple:describe())

This prints:

Wheat, day 1 of 2
Apple tree, day 1 of 30, gives apples

What's new:

  • local Tree = {} and Tree.__index = Tree make Tree a class, just like Crop.
  • setmetatable(Tree, {__index = Crop}) gives the class Tree a metatable: what Tree doesn't have, Lua looks for in Crop. This line is the inheritance. Tree is a subclass of Crop, and Crop is its parent class.
  • Tree.new doesn't repeat what Crop.new does. It calls Crop.new to make a crop with a name, days and age, then turns it into a tree with setmetatable(tree, Tree) (a table has only one metatable, so this replaces Crop), and adds the tree's own key, fruit.

When you call apple:grow(), Lua looks for grow step by step: in apple itself (no), in Tree through the apple's metatable (no), and in Crop through the metatable of Tree (yes). It's a chain: apple → Tree → Crop.

Overriding a method. Tree has its own describe. Lua stops looking at the first describe it finds, and for a tree, that's the one in Tree. So it replaces (overrides) the one in Crop. Wheat is a plain crop, so it still uses the describe from Crop. The tree's version doesn't have to repeat the parent's work: Crop.describe(self) calls the parent's method on the same tree. Notice the dot and self passed by hand. self:describe() would call the tree's own describe again, which would call itself again and again, until the program ends with stack overflow.

Typical mistakes:

  • Forgetting setmetatable(Tree, {__index = Crop}): trees don't find the methods of crops, and apple:grow() ends with attempt to call a nil value (method 'grow').
  • Forgetting setmetatable(tree, Tree) in Tree.new: the new tree stays an ordinary crop. apple:describe() then uses the version from Crop and says nothing about fruit, and the tree's own methods aren't found.
  • Expecting metamethods to be inherited. Lua looks for __tostring, __lt, __add and the others right in the object's metatable, not through __index. If Crop has __tostring, trees still print as table: 0x… until you add Tree.__tostring = Crop.__tostring.

Instructions

Below Animal:speak, start a class Cow that inherits from Animal: create the table, set its __index, and give it a metatable whose __index is Animal.

Add a constructor Cow.new(name). It creates the animal with Animal.new and the sound "moo", turns it into a cow with setmetatable, adds a key milk with the value 0, and returns the cow. Add a method Cow:giveMilk(liters) that adds liters to milk, too. At the end of the program, create Bella with Cow.new("Bella"), let her give 8 liters of milk and then 6, and print what she says. The program prints:

Rex says woof
Bella says moo

Override speak for cows: Cow:speak() returns what Animal.speak returns, followed by how much milk the cow has given. Rex is a plain animal, so he still just says woof. The program prints:

Rex says woof
Bella says moo and has given 14 liters of milk

Start programming for free

By signing up, you agree to the Terms of Service and Privacy Policy.

Or sign up with:

8/9