Even though the differents is small, there is still a difference.
Also Eventer is more memory efficient
Both of the events made the same thing
Eventer
Signal
This module still has a things I would like to optimize. Also I will add some more functionality to it.
I just wanted to share its early version.
Code
local Eventer = {}
local mt = {
__newindex = function(self,k,v)
for i,v in self.connections do
v.func()
if v.Once then table.remove(self.connections,i) end
end
end,
}
function Eventer.new(a)
local t : CustomEvent = {
connections = {}
}
function t:Connect(func)
table.insert(t.connections,{
func = func,
Once = false,
})
return {Disconnect = function() table.remove(t.connections,table.find(t.connections,func)) end}
end
function t:Once(func)
table.insert(t.connections,{
func = func,
Once = true,
})
end
function t:Fire(func)
t[1] = false
end
setmetatable(t,mt)
return t
end
return Eventer
I’d just like to add that your code is faster because it doesn’t create, or utilize threads. GoodSignal puts connections in a separate thread, which takes more time.
it would yield the current thread until the event fires. also, how well does this work when a connection yields?
edit on yielding connections: it doesn’t:
however, for simple use cases this is a very nice and easy solution. if you plan on having a simple event in an oop class that will run very often, this would be a good option to consider
Yea i havent really implemented it yet. It currently yields when there are multiple functions connected to it (due to its behaviour), i will update it once i either implement a thing im currently working on, or just coroutine them using task.spawn
local Eventer = {}
---- simplified funcs ----
local ts = task.spawn
local tw = task.wait
local ti = table.insert
local tc = table.clone
local tr = table.remove
local tf = table.find
---- function ----
local function DoEvent(self,...)
for i,v in self.connections do
ts(v.funcs,...)
if v.Once == true then table.remove(self.connections,i) end
end
if self.Fired == true then self.Fired = false end
end
local function Disconnect(self,i)
tr(self.connections,i)
end
---- general code ----
local mt = {
__call = DoEvent
}
export type Event<A...> = {
Fire: (any) -> (nil),
Wait: () -> (nil),
Connect: (Callback: () -> (any)) -> (nil),
Once: (Callback: () -> (any)) -> (nil)
}
local t : Event = {
connections = {},
Fired = false
}
function t:Connect(func)
ti(self.connections,{funcs = func})
local i = tf(self.connections,func)
return {Disconnect = function() tr(self,i) end}
end
function t:Once(func)
ti(self.connections,{
funcs = func,
Once = true
})
end
function t:Fire(...)
self(...)
end
function t:Wait()
self.Fired = true
repeat tw() until self.Fired == false
end
setmetatable(t,mt)
function Eventer.new()
local tab = tc(t)
return tab
end
return Eventer
I did some optimization and this is what i got. Any ideas?
--!nocheck
local Eventer = {}
---- simplified funcs ----
local ts = task.spawn
local tw = task.wait
local ti = table.insert
local tc = table.clone
local tr = table.remove
local tf = table.find
---- general code ----
export type Event<A...> = {
Fire: (any) -> (nil),
Wait: () -> (nil),
Connect: (Callback: () -> (any)) -> (nil),
Once: (Callback: () -> (any)) -> (nil)
}
local t : Event = {{}}
function t:Connect(func)
ti(self[1],func)
return {Disconnect = function() tr(self[1],tf(self[1],func)) end}
end
function t:Once(func)
ti(self[1],-#self[1],func)
end
function t:Fire(...)
for i,v in self[1] do
ts(v,...)
if i < 0 then table.remove(self[1],i) end
end
end
function t:Wait()
local Running = coroutine.running()
local defer = nil
self:Once(function()
if defer ~= nil then task.cancel(defer) end
task.defer(Running)
end)
return coroutine.yield()
end
function Eventer.new()
return tc(t)
end
return Eventer
i revamped some things and took your :Wait() to make my own (not really different from yours)
Somehow now it can be compared to GoodSignal (70% of the time Eventer is faster)
I’ve really been wanting to do something similar to this module with my own code but I’ve also been stuck thinking about the wait function. I had an idea, what if the connection wait() relied on another API that is versatile enough to provide the built-in wait, like a .Changed:Wait() signal?? (Maybe an instance value that resides underneath the module as a descendant, only created when calling the Wait()