--# obj is the OO table. do not define functions in here, they must be defined after this declaration for the __newindex metamethod to be invoked local obj = setmetatable({}, { __newindex = function(self, key, value) if type(value) == "function" then local func = setmetatable({}, { __call = function(_, ...) if rawequal(self, ({...})[1]) then return value(...) end return value(self, ...) end; }) rawset(self, key, func) else rawset(self, key, value) end end; }) --# so add functions to your object here, define them like detailed below function obj:foo() print(self) end function obj.bar(self) print(self) end --# from now on the above functions can be invoked in one of three ways obj:foo() obj.foo(obj) obj.foo() --# this is not normal OO, yet it still works due to the metatable magic.