Equality Checks
Part of the Object Oriented Programming section of Coddy's Lua journey — lesson 17 of 70.
You've seen how __tostring controls how an object displays itself. Another useful metamethod is __eq, which defines when two objects should be considered equal using the == operator.
By default, comparing two tables with == checks if they're the exact same table in memory. Two separate objects with identical data will return false:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Output: false (different tables)With __eq, you can define your own equality logic. In a class, you add it just like __tostring—as a function in the class table. For equality to work, both objects must share the same metatable:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endNow two User objects are considered equal if they share the same ID, regardless of other fields:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Output: true (same ID)
print(u1 == u3) -- Output: false (different IDs)This pattern is valuable when objects represent real-world entities with unique identifiers—comparing database records, game entities, or any objects where identity matters more than memory location.
Challenge
EasyLet's build a Product class that can determine if two products are the same item—even when they're stored in completely different tables! In retail systems, products often have unique SKU codes (Stock Keeping Units), and two products should be considered equal if they share the same SKU, regardless of other details like price changes.
You'll organize your code across two files:
Product.lua: Define yourProductclass with the standard prototype pattern. Each product should store asku(the unique identifier) and aname. Implement the__eqmetamethod so that two products are considered equal when they have the same SKU—the name doesn't matter for equality.main.lua: Require your Product module and create several product instances. Compare them using the==operator to see your custom equality logic in action.
Your Product class should include:
- A
:new(sku, name)constructor - A
:getInfo()method that returns a string in the format:[sku]: [name] - The
__eqmetamethod that compares products by their SKU
You will receive six inputs:
- SKU for the first product
- Name for the first product
- SKU for the second product
- Name for the second product
- SKU for the third product
- Name for the third product
In your main file, create three products using the provided inputs, then print:
- The info for each product (three lines)
- The result of comparing product 1 with product 2
- The result of comparing product 1 with product 3
For example, if the inputs are ABC123, Wireless Mouse, ABC123, Mouse (Updated), XYZ789, and Keyboard, the output should be:
ABC123: Wireless Mouse
ABC123: Mouse (Updated)
XYZ789: Keyboard
true
falseNotice how the first two products are equal (same SKU) even though their names differ—this is exactly how real inventory systems track products through name changes and updates!
Cheat sheet
The __eq metamethod defines custom equality logic for objects using the == operator.
By default, comparing two tables checks if they're the same table in memory:
local user1 = {id = 101, name = "Alice"}
local user2 = {id = 101, name = "Alice"}
print(user1 == user2) -- Output: false (different tables)To define custom equality, add __eq as a function in the class table. Both objects must share the same metatable:
local User = {}
User.__index = User
function User:new(id, name)
local instance = {}
setmetatable(instance, self)
instance.id = id
instance.name = name
return instance
end
function User:__eq(other)
return self.id == other.id
endNow objects are equal based on your custom logic:
local u1 = User:new(101, "Alice")
local u2 = User:new(101, "Bob")
local u3 = User:new(202, "Alice")
print(u1 == u2) -- Output: true (same ID)
print(u1 == u3) -- Output: false (different IDs)Try it yourself
-- Require the Product module
local Product = require('Product')
-- Read inputs
local sku1 = io.read()
local name1 = io.read()
local sku2 = io.read()
local name2 = io.read()
local sku3 = io.read()
local name3 = io.read()
-- TODO: Create three Product instances using the inputs
-- TODO: Print the info for each product (three lines)
-- TODO: Print the result of comparing product 1 with product 2
-- TODO: Print the result of comparing product 1 with product 3
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