Lua Object-Orientation Changing metamethods of an object


Example

Having

local Class = {}
Class.__meta = {__index=Class}
function Class.new() return setmetatable({}, Class.__meta)

Assuming we want to change the behavior of a single instance object = Class.new() using a metatable,

there are a few mistakes to avoid:

setmetatable(object, {__call = table.concat}) -- WRONG

This exchanges the old metatable with the new one, therefore breaking the class inheritance

getmetatable(object).__call = table.concat -- WRONG AGAIN

Keep in mind that table "values" are only reference; there is, in fact, only one actual table for all the instances of an object unless the constructor is defined as in 1, so by doing this we modify the behavior of all instances of the class.


One correct way of doing this:

Without changing the class:

setmetatable(
    object,
    setmetatable(
        {__call=table.concat},
        {__index=getmetatable(object)}
    )
)

How does this work? - We create a new metatable as in mistake #1, but instead of leaving it empty, we create a soft copy to the original metatable. One could say the new metatable "inherits" from the original one as if it was a class instance itself. We can now override values of the original metatable without modifying them.

Changing the class:

1st (recommended):

local __instance_meta = {__index = Class.__meta}
-- metatable for the metatable
-- As you can see, lua can get very meta very fast
function Class.new()
    return setmetatable({}, setmetatable({}, __instance_meta))
end

2nd (less recommended): see 1


1 function Class.new() return setmetatable({}, {__index=Class}) end