Object-Oriented Programming
17.1 The Colon Syntax
local obj = {value = 10}
function obj.get(self) return self.value end -- explicit self
function obj:get2() return self.value end -- colon adds an implicit self parameter
print(obj.get(obj), obj:get(), obj:get2()) -- obj:get() == obj.get(obj)17.2 Classes with Metatables
__tostring is looked up in the metatable (Account), so defining it as a method on Account works because Account is the metatable.
local Account = {}
Account.__index = Account -- instances look up methods in Account
function Account.new(owner, balance)
local self = setmetatable({}, Account)
self.owner = owner
self.balance = balance or 0
return self
end
function Account:deposit(amount)
if amount <= 0 then error("amount must be positive", 2) end
self.balance = self.balance + amount
return self -- allow chaining
end
function Account:withdraw(amount)
if amount > self.balance then return nil, "insufficient funds" end
self.balance = self.balance - amount
return true
end
function Account:__tostring() return string.format("Account(%s, %.2f)", self.owner, self.balance) end
local acc = Account.new("Ana", 100)
acc:deposit(50):deposit(25)
local ok, err = acc:withdraw(500)
print(acc, ok, err) --> Account(Ana, 175.00) nil insufficient funds17.3 Class Variables, Static Methods and Privacy
local Counter = {count = 0} -- class-level field
Counter.__index = Counter
function Counter.new() Counter.count = Counter.count + 1; return setmetatable({}, Counter) end
function Counter.total() return Counter.count end -- "static" (no self)
-- Privacy via closures
local function new_person(name)
local secret = "hidden" -- private
local self = {}
function self.get_name() return name end
function self.reveal() return secret end
return self
end
local p = new_person("Bo")
print(p.get_name(), p.secret) --> Bo nil17.4 Prototype-Based Style
local Animal = {sound = "..."}
function Animal:new(o)
o = o or {}
setmetatable(o, self) -- self is the prototype (class or parent instance)
self.__index = self
return o
end
function Animal:speak() return self.name .. " says " .. self.sound end
local dog = Animal:new{name = "Rex", sound = "Woof"}
print(dog:speak())