Let's try out the inheritance example from the official lua docs and declare everything this way:
Account = {
balance = 50,
receipt = function(self)
print(self.balance)
end,
new = function(self, o)
local o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
}
SpecialAccount = {
balance = 150,
special_receipt = function(self)
print(self.balance)
print("This is special!")
end,
}
-- Test ---------------------------
s = Account:new(SpecialAccount)
print(tostring(Account))
print(tostring(SpecialAccount))
print(tostring(s))
s:receipt()
s:special_receipt()
This is nice and the receipt-
functions work as expected, but there is a problem with s
:
It looks like s
is SpecialAccount
.
They are the same tables.
This is bad, because now you can not create several instances of SpecialAccount
.
What am I missing here?
It looks like s is SpecialAccount. They are the same tables.
Yes, s
is SpecialAccount
: Account:new(SpecialAccount)
makes SpecialAccount
extend Account
, returning SpecialAccount
(this should become apparent if you go through what :new
does and how the :
syntactic sugar works).
In Pseudocode, this might look as follows in a language supporting class-based OOP:
class Account { ... } // Account = ...
class SpecialAccount { ... } // SpecialAccount = ...
SpecialAccount extends Account; // s = Account:new(SpecialAccount)
Why return SpecialAccount
you may wonder? To make it read more naturally, as in a class-based language:
class SpecialAccount extends Account { ... }
you would write:
SpecialAccount = Account:new{
balance = 150,
special_receipt = function(self)
print(self.balance)
print("This is special!")
end,
}
It may be considered dirty to "overload" :new
both for instantiation and inheritance, but if you look closely, inheritance can be seen as a special form of instantiation.
This is bad, because now you can not create several instances of
SpecialAccount
This is incorrect. You can create an instance of SpecialAccount
just like you can create an instance of Account
: By calling :new
:
s = SpecialAccount:new() -- creates a new special account
assert(s ~= SpecialAccount)
you can also pass a table with some values if you like:
s = SpecialAccount:new{balance = 50}