Menu
Coddy logo textTech

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
end

Now you can check an object's type directly:

local buddy = Dog:new("Buddy")
print(buddy._type)  -- Output: Dog

For 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
end

This lets you filter mixed collections by class type—useful when you need to perform operations only on specific kinds of objects.

challenge icon

Challenge

Easy

Let'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 _type field 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 _type field to "Dragon". The constructor should accept a name and call the parent constructor.
  • Goblin.lua: Another child class inheriting from Creature with _type set to "Goblin". Same constructor pattern as Dragon.
  • main.lua: This is where you'll bring everything together. Create a helper function called filterByType(objects, typeName) that takes a table of objects and a type string, then returns a new table containing only objects whose _type matches the given type name.

You will receive four inputs:

  1. A dragon's name
  2. A goblin's name
  3. Another dragon's name
  4. The type to filter by (either Dragon or Goblin)

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
Ember

If 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
end

Child 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
end

Check an object's type by accessing the _type field:

local buddy = Dog:new("Buddy")
print(buddy._type)  -- Output: Dog

Create 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
end

Try 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
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming