Reputation: 331
I created a similar function to what is shown here, and am having trouble with the __add metamethod. I want to be able to use the __add metamethod on two instances of a Class, but the only way it seems to work is if I add the metamethods to the metatable of the instances. Is there a way I could set this up to work so that my class or its metatable can have the __add metamethod and work when adding instances together?
function Class(superClass, constructor)
local class = {};
local metatable = {};
if superClass then
metatable.__index = superClass;
end
setmetatable(class, metatable);
function metatable:__call(...)
local instance = {};
setmetatable(instance, { __index = class });
if class.constructor then
class.constructor(instance, ...);
end
return instance;
end
class.constructor = constructor;
return class;
end
Here is an example of what I would like to do:
A = Class(nil, function(self, num)
self.num = num;
end);
function A:__add(rhs)
return A(self.num + rhs.num);
end
a = A(1);
b = A(2);
c = a + b;
Upvotes: 1
Views: 135
Reputation: 287
Just in case it helps, this is how I usually create my classes (supports inheritance easily, too):
function Vector(x, y)
local self = {}
self.x = x
self.y = y
self.magnitude = math.sqrt(x*x + y*y)
function self.unit()
return Vector(x/self.magnitude, y/self.magnitude)
end
function self.printComponents()
print("[" .. self.x .. ", " .. self.y .. "]")
end
--if you want to implement metamethods...
setmetatable(self, {
__add = function(_, other)
return Vector(self.x + other.x, self.y + other.y)
end
})
return self
end
-- now, let's make a ComplexNumber class that inherits from Vector
function ComplexNumber(a, b)
-- define self as an instance of Vector
local self = Vector(a, b)
-- override Vector.printComponents()
function self.printComponents()
print(self.x .. " + " .. self.y .. "i")
end
return self
end
--examples
local v = Vector(10, 20)
v.printComponents() --> [10, 20]
local c = ComplexNumber(10, 5)
c.printComponents() --> 10 + 5i
Upvotes: 0
Reputation: 331
Thanks to the help of Colonel Thirty Two and Etan Reisner, I came up with the following solution:
function metatable.__call(self, ...)
local instance = {};
setmetatable(instance, self);
if class.constructor then
class.constructor(instance, ...);
end
return instance;
end
I changed the function so that it no longer hides the self variable, and use it as the metatable for the instance. Adding now works as intended. However, it caused issues elsewhere.
I tried a few things I found elsewhere and came up with this working solution:
function Class(superClass, constructor)
local class = {};
if superClass then
for k,v in pairs(superClass)
do
class[k] = v;
end
class._superClass = superClass;
end
class.__index = class;
local metatable = {};
function metatable:__call(...)
local instance = {};
setmetatable(instance, class);
if class.constructor then
class.constructor(instance, ...);
end
return instance;
end
class.constructor = constructor;
setmetatable(class, metatable);
return class;
end
Upvotes: 1