Has-A Relationship
Part of the Object Oriented Programming section of Coddy's Lua journey. Lesson 49 of 70.
Throughout this course, you've used inheritance to share behavior between classes—a Dog "is an" Animal. But inheritance isn't always the right tool.
Sometimes, objects don't share a family tree; instead, one object simply contains another. This is called composition, and it models a "has-a" relationship.
Consider a car. A car isn't a type of engine—it has an engine. The engine is a separate object that exists inside the car:
local Engine = {}
Engine.__index = Engine
function Engine:new(horsepower)
local obj = {horsepower = horsepower}
setmetatable(obj, Engine)
return obj
end
local Car = {}
Car.__index = Car
function Car:new(model, engine)
local obj = {
model = model,
engine = engine -- Store the Engine object inside Car
}
setmetatable(obj, Car)
return obj
endWhen creating a car, you pass an existing engine object to its constructor:
local myEngine = Engine:new(200)
local myCar = Car:new("Sedan", myEngine)
print(myCar.engine.horsepower) -- 200The car doesn't inherit from the engine—it simply holds a reference to one. This keeps both classes independent. You could swap in a different engine, or use the same engine class in a motorcycle.
Composition gives you flexibility that inheritance can't: you're assembling objects from parts rather than locking them into a rigid family hierarchy.
Challenge
EasyLet's build a computer system using composition! Instead of inheritance, you'll create a Computer that has a CPU inside it—demonstrating the "has-a" relationship.
You'll organize your code across three files:
CPU.lua: Create a CPU class with a constructor:new(brand, speed)that stores the brand name and speed in GHz. Include a:getInfo()method that returns a string in the format:{brand} @ {speed}GHzComputer.lua: Create a Computer class whose constructor:new(model, cpu)accepts a model name and a CPU object. The Computer stores the CPU object inside itself (composition!). Include a:describe()method that prints the computer's model and its CPU's info.main.lua: Bring everything together! Read inputs for the CPU brand, CPU speed, and computer model. Create a CPU object first, then pass it to the Computer constructor. Finally, call the computer's:describe()method.
You will receive three inputs:
- The CPU brand (a string)
- The CPU speed in GHz (a number)
- The computer model name (a string)
Your output should show the computer's description, which includes information from its contained CPU:
Model: {model}
CPU: {brand} @ {speed}GHzFor example, if the inputs are Intel, 3.5, and WorkStation, the output should be:
Model: WorkStation
CPU: Intel @ 3.5GHzNotice how the Computer doesn't inherit from CPU—it simply holds a reference to one. The Computer's :describe() method accesses the CPU's data through the stored object, showing how composition lets you build complex objects from simpler parts!
Try it yourself
-- main.lua
-- Bring everything together using composition
local CPU = require('CPU')
local Computer = require('Computer')
-- Read inputs
local cpuBrand = io.read()
local cpuSpeed = tonumber(io.read())
local computerModel = io.read()
-- TODO: Create a CPU object with the brand and speed
-- TODO: Create a Computer object with the model and the CPU object
-- TODO: Call the computer's describe() method to print the output
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 ClassCircle ClassPerimeter MethodShape CollectionTotal AreaFilter Shapes2Class 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 Hierarchy9Composition & Mixins
Has-A RelationshipDelegationSimple MixinsApplying Multiple MixinsMixins vs InheritanceRecap - Robot AssemblyPractice on your own: Online Lua compiler