2

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?

tyrondis
  • 3,364
  • 7
  • 32
  • 56

1 Answers1

3

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.

Oka
  • 23,367
  • 6
  • 42
  • 53
  • 1
    Thanks! That was helpful. However, I am not quite understanding option 3. What would be a typical use case? – tyrondis Aug 16 '16 at 11:37
  • 1
    @tyrondis Option three is mostly an example of how _arbitrary_ a table's metatable can be. It can be useful in that the instance gets to control its own metamethods, without a separate metatable like in option two. [Here is an example](https://github.com/Okahyphen/base/blob/master/src/base.lua), though it is a bit terse. – Oka Aug 16 '16 at 11:45
  • 1
    Gotcha! Thanks for your help! – tyrondis Aug 16 '16 at 11:51