Search code examples
inheritanceluaprototypemetatable

Difference in Lua metatable __index positioning


I keep seeing two ways of defining the __index on a metatable:

Account = {}
Account.__index = Account

function Account.create(balance)
   local self = { balance = balance }
   return setmetatable(self, Account)
end

Or:

Account = {}

function Account.create(balance)
   local self = { balance = balance }
   return setmetatable(self, { __index = Account })
end

I can't quite grasp what the difference in behaviour is between the two. Can somebody enlighten me?


Solution

  • The difference is the number of tables created, and the table chain created.

    In the first example, Account doubles as a shared metatable for all instances as well as the lookup destination for the __index metamethod. Creating a chain like:

    instance -> Account, __index -> Account
    

    In the second example, each instance returned from the create method has its own, unique metatable which acts as the bridge between the instance and the 'class'. The chain created:

    instance -> (anonymous, unique table), __index -> Account
    

    Sometimes you'll also see tables act as their own metatables:

    Account = {}
    
    function Account.create(balance)
       local self = { balance = balance, __index = Account }
       return setmetatable(self, self)
    end
    

    Which creates this chain:

    instance -> instance, __index -> Account
    

    The benefits of the first and third styles are less tables created, which can simplify some implementations, and reduce memory footprints. The second style is arguably more robust, since each instance gets its own metatable that can then be manipulated individually.

    The style you use really depends on the requirements of your program, and how comfortable you are with implementing any given style.