I’m using a metatable and have a custom __index metamethod defined here:
local option = {}
function option.__index(self, key: any)
if key == "is_some" then
return self.__value ~= math.huge + 1
elseif key == "is_none" then
return self.__value == math.huge + 1
end
return self[key]
end
Whenever I try calling a method on the option object it just gives me a stack overflow error.
How do I stop this? Using rawget() just removes the metatable part.
you need rawget for all indexes of self, in the if-elseif statement and in the return statement because they all cyclically invoke the __index metamethod. Here’s a fixed version:
--not sure what dynamic type <T> was for so removed it
function option:__index(key: any)
if (key == "is_some") then
return rawget(self, "__value") ~= math.huge + 1
elseif (key == "is_none") then
return rawget(self, "__value") == math.huge + 1
else
return rawget(self, key)
end
end
Yes, but even though it can’t be both at the same time, both branches index self.__value, where self points to obj, so __index is re-invoked no matter the branch.
local option = {}
function option.__index<T>(self, key: any)
if key == "is_some" then
return self.__value ~= math.huge + 1
elseif key == "is_none" then
return self.__value == math.huge + 1
end
return rawget(self, key)
end
function option.new(value)
return setmetatable({
__value = value
}, option)
end
function option.unwrap(self)
return self.__value
end
return option
It’s able to return __value when I get it directly.
But when I try running the option function it doesn’t work.
local CustomMethods = {}
function CustomMethods.unwrap(self)
return self.__value
end
function option.__index<T>(self, key)
if key == "is_some" then
return self.__value ~= math.huge + 1
elseif key == "is_none" then
return self.__value == math.huge + 1
end
return setmetatable(table.clone(self), {
__call = CustomMethods[key]
}) or rawget(self, key)
end
I keep all the methods in a CustomMethods function. When I call a custom method then it just returns a new metatable using the original self.
Just have actual methods in your __index in table shorthand
Your setup is somewhat convoluted and I just have to ask, to what end? I hope you consider if you really need to implement it in this way, as it definitely isn’t this complicated to just get a monad for nil.
The reason it says ‘Attempt to call a nil value’ is because when __index is run, it never returns the function from the metatable. It just returns the key of option from the table itself, which is nil. Remember, the method is in the metatable, not the table.