As The last ship sailed towards the distant horizon I sat there watching on a rock My mind slowly drifting away Forming into my... Dreamtale
Class in Lua
2018-05-27 / 5 min read

Translate from https://wuzhiwei.net/lua_make_class/

How to implement Class in Lua

There is not a type called Class in Lua, but we could implement it in Lua.

What is Class

To implement Class, we should know what class is.

In my opinion, Class is a self-defined variable type, it defined some properties and functions, is a collection of Properties and Functions.

What is instance

Based on the understanding of Class is a table full of key-value mapping pairs.

An instance is a collection of properties and functions which created with class as a template.

Syntactic sugar

Try to create a Person

Person = { name = "Suntabu" }

above codes inited Person as a table, this table has a key named name, its default value is 'I am a lazy person'.

So a person should have a property named name.

Then give this person the ability to talk:

Person.talk = function(self,words)
    print(self.name .. " says: " .. words)
end

above codes added a key-value pair: key -> talk, value -> a function.

Then, invoke it by Person.talk(Person, "Hello")
Results out: Suntabu says: Hello

Another form of function:

function Person.talk(self, words)
    print(self.name .. " says: " .. words)
end

and we could use : to omit self, it's just a syntactic sugar

function Person:talk(words)
    print(self.name .. " says: " .. words)
end

so Person.talk -> Person:talk
but in function body, we still could use self.

How to find elements in table

Assuming find a key named talk in table p, the find flow:

Does talk exist in p? Yes --> return p['talk']
        |
        No
        |
Was metatable of p set? Yes --> return nil
        |
        No
        |
Does __index exist in metatable of p? No --> return nil
        |
        Yes
        |      
Does talk exist in the __index in metatable of p 
corresponding table?                No --> return nil
        |
        Yes,return getmetatable(p).__index.talk

Understanding of metatable

metatable is a table actually.

global functions of metatable
setmetatable(t,m)  -- set metatable of t as m.
getmetatable(t)    -- return metatable m of t

TIPS: all tables could be set metatable, and new created table has no metatable if not set.

metamethod

Lua defined keys, such as __index __add __concat and so on, These key names are all prefixed with a double underscor __. The corresponding value is a function called metamethod, which defines the operation you want to customize the table.

TIPS: The __index attribute of the metatable can also be a table

Considering codes below:

--create metatable m,defined __add and its function
local m = {
  __add = function(t1, t2)
    local sum = {}
    for key, value in pairs(t1) do
      sum[key] = value
    end
 
    for key, value in pairs(t2) do
      if sum[key] then
        sum[key] = sum[key] + value
      else
        sum[key] = value
      end
    end
    return sum
  end
}
 
--set metatables of table1 and table2 as m
local table1 = setmetatable({10, 11, 12}, m)
local table2 = setmetatable({13, 14, 15}, m)
 
--table could not operate + ,but with the help of metatable, we did it!
for k, v in pairs(table1 + table2) do
  print(k, v)
end
--print
--1 23
--2 25

Implementaion of table

For example:

--set Person's __index as self
Person.__index = Person   
 
--p is a instance
local p = {}
 
--set metatable of p as Person
setmetatable(p, Person)
 
p.name = "Suntabu"
 
--p was originally an empty table, no talk exists in it.
--with metatable,and set metatable's __index as table Person
--Person has the property of talk, then invoke it.
p:talk("I am Suntabu") 
 
--prints out
--Suntabu say: I am Suntabu

For convienient, we add a function create to Person:

function Person:create(name)
    local p = {}
    setmetatable(p, Person)
    p.name = name
    return p
end
 
local pa = Person:create("A")
local pb = Person:create("B")
pa:talk("I am A") --A says: I am A
pb:talk("I am B") --B says: I am B

Links: