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?
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.