--[[ object oriented interface ]-------------------------------------------- Syntax: = class(name: string [, parent1 [, parent2 [, ...] ] ]) Example: c = class('test') -- constructor: constructor has the name of the class function c:test(x) self.x = x end -- new (always! virtual) method function c:call() print('test:call()') end -- implement the metamethod __tostring -- methametods are initialized at first instantiation of the class, so -- they cannot be defined after instantiation function c:__tostring() return "my test object ("..self.x..")" end -- __call function c:__call(...) print('function c:__call('..table.concat(arg, ', ')..')') end -- create a new instance of our class v = c:new(19) -- try __tostring print(v) v(10, 20) -- derive our class! d = class('derived', c) -- constructor function d:derived(x) self:test(x) end function d:__tostring() return "derived!" end function d:call() print('d:call()') self.inherited['test'].call(self) end v = d:new(10) -- try __tostring print(tostring(v)) v('hello world!', ':)') v:call() --------------------------------------------------------------------------]] -- class definition function local metas = { "__add", "__sub", "__mul", "__div", "__pow", "__unm", "__eq", "__lt", "__le", "__concat", "__call", "__tostring" } function class(name, ...) local __parent = arg local members = { __parent = __parent, __name = name, } local mt = { __metatable = members, __index = members } -- function used to create a new instance of the function local init = false members.new = function(self, ...) -- initialize metatable metamethods if (not init) then for _, v in pairs(metas) do mt[v] = members[v] end init = true end -- set metatable local o = setmetatable({}, mt) -- call constructor o[name](o, unpack(arg)) return o end -- default constructor - pass the parameters to the parent constructors members[name] = function(self, ...) for i = 1, __parent.n do local p = __parent[i] p[p.__name](self, unpack(arg)) end end -- function used to access parent local function inherit(t,name) -- recurse over the parent list local function inh(p) if (p.__name == name) then return p end p = p.__parent local b for i = 1, p.n do b = inh(p[i]) if (b) then return b end end end return inh(members) end members.inherited = {} local imt = { __metatable = inherit, __index = inherit } setmetatable(members.inherited, imt) -- set metatable if (arg.n == 1) then -- only one parent class setmetatable(members, {__metatable = __parent[1], __index = __parent[1]}) elseif (arg.n > 1) then -- several parent classes setmetatable(members, { __index = function(_, key) -- slow. need to go through all parents manualy for i = 1, arg.n do local parentmethod = __parent[i][key] if parentmethod then return parentmethod end end end, __metatable = __parent }) end return members end