Event connections not actually erroring?

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
image

When running this it will print this
image

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
image

Even if I literally pass in “1” it still attempts to call it???

image

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.

3 Likes

You forgot the () on Class, still I don’t think that’s going to work.

Try something like this:

local Connection = script.Event.Event:Connect(fucntion(Data)
    Class(Data)
end)

If this does not work:

local Connection = script.Event.Event:Connect(Class())

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()

(so i can run other class methods in connections)

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

Actually I just tested it I have no idea why it still works

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")

Screenshot_1

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

Yeah since Touched is built in to the object, or you could use region3.

nvm I forgot you can’t do diagonal on region3

pcall doesn’t hide the error.

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"})