Hello, I am trying to use a “special function” class I made that will save the arguments and run the function with x arguments (mostly for running class methods without the extra memory usage) it utilizes the __call metamethod to reroute the call.
However I came across a problem, when I tried to pass in my class with an __call metamethod to a connection I got an error!!! I would understand if this simply isn’t supported but my things still worked!
so I did a bit of testing and I came up with this
When running this it will print this
as you can see it throws an error. “Attempt to connect failed: Passed value is not a function” BUT IT WORKS, although it throws an error it doesn’t cancel the thread and the script works!
Even if I remove the __call metamethod from the metatable it STILL CONNECTS
Even if I literally pass in “1” it still attempts to call it???
I would post this in studio bugs but I don’t have the regular status. I could just put it in a pcall to hide the error but this is a big oversight on roblox’s part. I hope they end up checking if tables have an __call metamethod before throwing an error, and actually throw a script yielding hard error if it isn’t there.
basically using function there takes up more memory, I was using the __call metatable hoping the Connection will treat it as a function (which it did but not before erroring)
My SpecialFunction class is like
function E(arg1, arg2)
--Arg1 is Hello as defined on the SpecialFunction.new thing
--Arg2 is World as defined on the actual call
end
local SpecFunc = SpecialFunction.new(TargetFunction, "Hello")
SpecFunc("World")
the usage case for this is you wouldn’t need to make a new function that has to save new bytecode, just run it under its “environment”
local SpecFunc = SpecialFunction.new(Class.RunFunction, Class)
--SpecFunc is always going to run Class.RunFunction in the class defined no matter where it is
SpecFunc()
That’s not possible you are using a table, the use of __call is when you call the table as a function; Class(). Other alternative would be something like this if you still want to use a table:
local Class = {
Handler = function(Data)
...
end
}
script.Event.Event:Connect(Class.Handler)
Or the direct approach:
local function Handler(Data)
...
end
script.Event.Event:Connect(Handler)
The reason that it does not stop the script is because Connect is a separate thread. Which in this case you passed a table, an error occurred but it still print’s the Connection.
when it threw a connect error “could not connect” should mean it isn’t able to connect, It connected just fine just threw the error… as it detects when it gets fired again…
plus im using metatable classes, the functions aren’t IN the class definitions, they are in the __index metatable
(class format)
local Module = {}
Module.__index = Module
function Module:DoSomething()
--This REQUIRES self, which is why i made the special function class to begin with
end
function Module.new()
local Obj = setmetatable({}, Module)
return Obj
end
if I just do script.Event.Event:Connect(Obj.Handler) it isn’t going to pass in self like if you call it using a colon
I already made a custom event class for myself that allows me to create “standalone” events without the need of a bindableevent instance. It works perfectly with my event class because im not actually checking if it’s a function
Wait hold on I think I know why it still works though my methods kind of messy, I just tried to imagine what a method Connect looks like:
local RunService = game:GetService("RunService")
local Event = {}
Event.__tostring = function()
return "Connection"
end
function Event:Connect(Handler)
local Connection = setmetatable({}, self)
table.insert(Event, Handler)
return Connection
end
function Event:Fire(...)
local args = {...}
for _, Handler in ipairs(self) do
local c
c = RunService.Heartbeat:Connect(function()
c:Disconnect()
Handler(unpack(args))
end)
end
end
local Test = setmetatable({}, {
__call = function(self, Data)
print(self, Data)
end,
})
local Connection = Event:Connect(Test)
print(Connection)
Event:Fire("Fire 1")
Event:Fire("Fire 2")
Event:Fire("Fire 3")
ye, my event class is basically that but the usage is kinda different
local Event = EventClass.new()
local Test = setmetatable({}, {
__call = function(self)
print("i was called")
end
})
local Connection = Event:Connect(Test)
Event:Fire("1")
Event:Fire("2")
Connection:Disconnect()
--it also has wait functionality but im too lazy to display it
but that’s beside the point. for events like part.Touched I can’t just use my custom class, I have to use roblox’s
local Class = setmetatable({}, {__call = function(Table, ...)
print(Table)
for Key, Value in pairs{...} do
print(Key, Value)
end
end})
local Event = Instance.new("BindableEvent")
pcall(Event.Event.Connect, Event.Event, Class)
Event:Fire({Key = "Value"})