Checking Type
Part of the Object Oriented Programming section of Coddy's Lua journey — lesson 41 of 70.
Duck typing is flexible, but sometimes you need to know what kind of object you're dealing with. Since Lua doesn't have built-in class types, you need to implement type checking yourself.
The simplest approach is adding a _type field to each class that identifies it:
local Animal = {}
Animal.__index = Animal
Animal._type = "Animal"
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
end
local Dog = {}
Dog.__index = Dog
Dog._type = "Dog"
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
endNow you can check an object's type directly:
local buddy = Dog:new("Buddy")
print(buddy._type) -- Output: DogFor more robust checking, you can create a helper function that examines the metatable chain:
local function isType(obj, typeName)
return obj._type == typeName
end
local function filterByType(objects, typeName)
local result = {}
for _, obj in ipairs(objects) do
if isType(obj, typeName) then
table.insert(result, obj)
end
end
return result
endThis lets you filter mixed collections by class type—useful when you need to perform operations only on specific kinds of objects.
Challenge
EasyLet's build a creature management system where you can filter a mixed collection of creatures by their type! You'll create a hierarchy of creature classes, each with a _type field, and then write a helper function to filter collections based on type.
You'll organize your code across four files:
Creature.lua: Your base class with a_typefield set to"Creature". Include a:new(name)constructor that stores the creature's name, and a:getName()method that returns it.Dragon.lua: A child class that inherits from Creature. Set its_typefield to"Dragon". The constructor should accept a name and call the parent constructor.Goblin.lua: Another child class inheriting from Creature with_typeset to"Goblin". Same constructor pattern as Dragon.main.lua: This is where you'll bring everything together. Create a helper function calledfilterByType(objects, typeName)that takes a table of objects and a type string, then returns a new table containing only objects whose_typematches the given type name.
You will receive four inputs:
- A dragon's name
- A goblin's name
- Another dragon's name
- The type to filter by (either
DragonorGoblin)
In your main file, create the three creatures (Dragon, Goblin, Dragon in that order), store them all in a single table, then use your filterByType function to get only the creatures matching the requested type. Loop through the filtered results and print each creature's name using :getName().
For example, if the inputs are Smaug, Gruk, Ember, and Dragon, the output should be:
Smaug
EmberIf the filter type were Goblin instead, only Gruk would be printed.
This demonstrates how adding a _type field to your classes enables you to identify and filter objects by their class—useful when working with mixed collections where you need to perform operations on specific types only!
Cheat sheet
In Lua, you can implement type checking by adding a _type field to each class:
local Animal = {}
Animal.__index = Animal
Animal._type = "Animal"
function Animal:new(name)
local obj = {name = name}
setmetatable(obj, Animal)
return obj
endChild classes should also define their own _type:
local Dog = {}
Dog.__index = Dog
Dog._type = "Dog"
setmetatable(Dog, {__index = Animal})
function Dog:new(name)
local obj = Animal.new(Animal, name)
setmetatable(obj, Dog)
return obj
endCheck an object's type by accessing the _type field:
local buddy = Dog:new("Buddy")
print(buddy._type) -- Output: DogCreate helper functions to check types and filter collections:
local function isType(obj, typeName)
return obj._type == typeName
end
local function filterByType(objects, typeName)
local result = {}
for _, obj in ipairs(objects) do
if isType(obj, typeName) then
table.insert(result, obj)
end
end
return result
endTry it yourself
-- main.lua: Bring everything together
local Dragon = require('Dragon')
local Goblin = require('Goblin')
-- Read inputs
local dragonName1 = io.read()
local goblinName = io.read()
local dragonName2 = io.read()
local filterType = io.read()
-- TODO: Implement the filterByType function
-- It takes a table of objects and a type string
-- Returns a new table containing only objects whose _type matches typeName
function filterByType(objects, typeName)
local result = {}
-- TODO: Loop through objects and check _type field
return result
end
-- TODO: Create three creatures (Dragon, Goblin, Dragon in that order)
-- TODO: Store all creatures in a single table
-- TODO: Use filterByType to get creatures matching the requested type
-- TODO: Loop through filtered results and print each creature's name
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