100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Object-Oriented Lua

Learn how Lua uses tables, functions, and metatables to build objects, methods, and encapsulation without a built-in class system.

OOP & ModulesIntermediate9 min readJul 10, 2026
Analogies

Objects Without a Class Keyword

Lua has no built-in class keyword. Instead, objects are ordinary tables that hold both data (fields) and behavior (functions stored as fields). A "method" is simply a table entry whose value happens to be a function, and "object-oriented" style in Lua is really just a convention for organizing tables and using the colon : syntax to pass the table itself as an implicit first argument, traditionally named self.

🏏

Cricket analogy: A batter's stats table in a scoring app is just a table with runs, balls, and a strikeRate() function attached to it, the same way Virat Kohli's profile bundles data and calculated behavior together rather than needing a separate 'BatterClass' definition.

lua
-- A simple object as a table
local dog = {}
dog.name = "Rex"
dog.sound = "Woof"

function dog.speak(self)
  print(self.name .. " says " .. self.sound)
end

dog.speak(dog)      -- explicit self
dog:speak()         -- colon sugar, identical result

The Colon Operator and self

The colon obj:method(args) is syntactic sugar for obj.method(obj, args). When you define a function with function obj:method(args) ... end, Lua automatically inserts self as the first parameter. This convention lets a single function definition work for any table that shares the same shape, because self refers to whichever table is on the left of the colon at call time, not a fixed object baked into the function.

🏏

Cricket analogy: When a commentator says 'Rohit Sharma plays a cover drive,' the shot technique is the same function applied with Rohit as the implicit subject, just as player:cover_drive() inserts whichever player table is self.

Constructors and Encapsulation

There is no new keyword; instead, programmers write a plain function (often called Dog.new() or via Dog.__index = Dog) that creates a fresh table, sets its fields, and returns it. Encapsulation is achieved by convention rather than enforcement: fields prefixed with an underscore, or values stored in a closure rather than the table itself, signal "private" data, since Lua has no private or public access modifiers.

🏏

Cricket analogy: A scorer manually filling in a fresh scorecard for every new match, rather than the stadium providing a pre-built 'MatchClass', mirrors how Lua's Dog.new() builds a table from scratch each time.

By convention, Lua OOP libraries name the table that holds shared methods after the "class" itself (e.g. Dog), and instances are separate tables whose metatable's __index points back to Dog. This pattern is covered in depth in the next topic, Inheritance with Metatables.

Why Convention Instead of Enforcement

Because Lua is a minimal, embeddable language, its designers chose not to bake in OOP mechanics, leaving library authors free to implement classes, prototypes, mixins, or purely functional styles as needed. This is why frameworks like middleclass, classic.lua, and 30log exist purely as small Lua libraries built from tables and metatables, not language extensions, and why understanding raw tables and self is essential before using any of them.

🏏

Cricket analogy: The ICC lets each cricket board decide its own domestic tournament format rather than mandating one globally, just as Lua leaves OOP style up to library authors instead of enforcing one class system.

  • Lua has no built-in class keyword; objects are ordinary tables holding data fields and function-valued methods.
  • The colon syntax obj:method(args) is sugar for obj.method(obj, args), automatically passing the table as self.
  • Constructors are plain functions (commonly named .new()) that build and return a fresh table, since new is not a reserved word.
  • Encapsulation is convention-based; Lua has no private/public modifiers, so underscore-prefixed names or closures signal restricted access.
  • Popular OOP libraries like middleclass and classic.lua are implemented entirely in Lua using tables and metatables, not language features.
  • Understanding raw tables and how self binds at call time is a prerequisite for using metatable-based inheritance.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#LuaStudyNotes#ObjectOrientedLua#Object#Oriented#Lua#Objects#OOP#StudyNotes#SkillVeris