Extending the Constructor
Part of the Object Oriented Programming section of Coddy's Lua journey — lesson 33 of 70.
When a child class inherits from a parent, you often want the child's constructor to initialize everything the parent would—plus any additional fields specific to the child. Instead of duplicating code, you can call the parent's constructor directly.
The technique involves using the parent class name to invoke its :new() method, passing the parent class as the first argument. You can do this with dot syntax: Vehicle.new(Vehicle, speed), or equivalently with colon syntax: Vehicle:new(speed) — both are valid and produce the same result. This creates the base object with all parent initialization, which you then customize for the child.
local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle:new(speed)
local obj = {speed = speed}
setmetatable(obj, Vehicle)
return obj
end
-- Car inherits from Vehicle
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})
function Car:new(speed, brand)
local obj = Vehicle.new(Vehicle, speed) -- Call parent constructor
obj.brand = brand -- Add child-specific field
setmetatable(obj, Car) -- Re-link to Car
return obj
endNotice the key steps in the child constructor: first, we call Vehicle.new(Vehicle, speed) (or equivalently Vehicle:new(speed)) to get an object with the speed field already set. Then we add the child-specific brand field. Finally, we change the metatable from Vehicle to Car so the instance looks up methods in the child class first.
local myCar = Car:new(120, "Toyota")
print(myCar.speed) -- Output: 120
print(myCar.brand) -- Output: ToyotaThis pattern keeps your code DRY—shared initialization logic lives in the parent, while each child only handles its unique attributes.
Challenge
EasyLet's build a creature hierarchy where a child class extends its parent's constructor! You'll create an Animal parent class and a Bird child class, where Bird's constructor calls Animal's constructor to handle shared initialization before adding its own unique attribute.
You'll organize your code across three files:
Animal.lua: Define your parent class with a:new(name)constructor that stores the animal's name. Include a:describe()method that prints the animal's name. Set up the standard class pattern with__indexand return the class.Bird.lua: Define your child class that inherits from Animal. Your Bird's:new(name, wingspan)constructor should call the parent constructor usingAnimal.new(Animal, name)to initialize the name, then add thewingspanfield to the object, and finally re-link the metatable to Bird. Include a:info()method that prints both the name and wingspan in a specific format.main.lua: Require your Bird module, read two inputs (name and wingspan), create a Bird instance, and call both methods to demonstrate that inherited and child-specific functionality work together.
You will receive two inputs:
- The bird's name
- The bird's wingspan (a number)
In your main file, create a Bird with the given name and wingspan. Then call :describe() followed by :info() on separate lines.
The :describe() method (inherited from Animal) should print:
Animal: {name}The :info() method (defined in Bird) should print:
{name} has a wingspan of {wingspan}For example, if the inputs are Eagle and 200, the output should be:
Animal: Eagle
Eagle has a wingspan of 200The key here is that your Bird constructor doesn't duplicate the name initialization—it delegates that work to Animal's constructor, then adds only what's unique to birds. This keeps your code DRY while building a proper inheritance chain!
Cheat sheet
To call a parent class constructor from a child class, use the parent class name with dot syntax, passing the parent class itself as the first argument:
local obj = ParentClass.new(ParentClass, parentArgs)After calling the parent constructor, add child-specific fields and re-link the metatable to the child class:
local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle:new(speed)
local obj = {speed = speed}
setmetatable(obj, Vehicle)
return obj
end
local Car = {}
Car.__index = Car
setmetatable(Car, {__index = Vehicle})
function Car:new(speed, brand)
local obj = Vehicle.new(Vehicle, speed) -- Call parent constructor
obj.brand = brand -- Add child-specific field
setmetatable(obj, Car) -- Re-link to Car
return obj
end
local myCar = Car:new(120, "Toyota")
print(myCar.speed) -- Output: 120
print(myCar.brand) -- Output: ToyotaThis pattern keeps initialization logic DRY—shared setup lives in the parent, while children only handle their unique attributes.
Try it yourself
-- main.lua: Entry point
local Bird = require('Bird')
-- Read inputs
local name = io.read()
local wingspan = tonumber(io.read())
-- TODO: Create a Bird instance with the given name and wingspan
-- TODO: Call :describe() on the bird (inherited from Animal)
-- TODO: Call :info() on the bird (defined in Bird)
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