Reputation: 403
I'm having quite a bit of trouble understanding OOP in Lua. According to Programming in Lua, I can create classes very simply, like this:
Class = {}
function Class:new()
setmetatable({}, self)
self.__index = self
self.a = 1
return self
end
function Class:incr()
self.a = 2 * self.a
return self
end
However, when I go and create an instance, it doesn't work as I would expect:
-- works as expected
instance = Class:new()
instance:incr()
print(instance) --> table 0x(address)
print(instance.a) --> 2
-- it gets weird from here on
other = Class:new()
other:incr():incr()
print(other) --> table 0x(same address)
print(other.a) --> 4
print(instance.a) --> 4
What am I doing wrong?
Upvotes: 1
Views: 126
Reputation: 964
function Class:new()
...
return self -- self is -> Class = {}
end
other = Class:new() -- Other will get Class = {} when you call new()
instance = Class:new() -- same here
print(other) -- will print Class = {}
print(instance) -- will print Class = {}
Upvotes: 1
Reputation: 5544
The example in PiL is frankly confusing. It describes what's called prototypal inheritance. That means that there's no distinction between classes and objects. Here is a version of your new
method which is slightly more correct:
function Class:new()
-- Note that self refers to the class, here. We have to return a new object.
self.__index = self
local o = {a=1}
setmetatable(o, self)
return o
end
But we still have a problem: Since our constructor sets an instance variable, we can't use it to make subclasses. If we try, those subclasses will all have a
set within themselves, instead of in their instances. We could define an init
method that we have to call every time we create a new instance, but that would be a pain. Here is one possible way to keep classes and objects separate:
-- Make sure every class has an __index pointing to itself. This lets it be the
-- metatable for both instances and subclasses.
local Class = {}
Class.__index = Class
function Class:new()
local o = {a=1}
setmetatable(o, self)
return o
end
function Class:incr()
self.a = 2 * self.a
return self
end
-- To inherit, simply use Class as the metatable.
local Subclass = {}
Subclass.__index = Subclass
setmetatable(Subclass, Class)
This way, new
is used only for creating instances.
Upvotes: 1