Signal Module V1

Basic Signal V1
I came up with a module that will help you in OOP Coding A simple and useful module compared to its alternatives

This is an oop example prepared to explain the use of the BasicSignal Module:

--!strict

local Signal = {}
Signal.__index = Signal

local Connection = {}
Connection.__index = Connection

export type Connection = {
	index : number,
	signal : Signal,

	Disconnect : (Connection) -> ()
}

export type Signal = {
	Connections : {[number] : (any) -> ()},

	Fire : (Signal, any) -> (),
	Connect : (Signal, callBack : (any) -> ()) -> Connection,
	Once : (Signal, callBack : (any) -> ()) -> (),
	Wait : (Signal, timeout : number) -> (),
}

function Signal:Fire(...)
	for i, v in pairs(self.Connections) do
		v(...)
	end
end

function Signal:Connect(callBack : (any) -> ()) : Connection
	table.insert(self.Connections, callBack)
	local index : number? = table.find(self.Connections, callBack)
	
	return setmetatable({
		index = index,
		signal = self :: Signal
	}, Connection) :: any
end

function Signal:Once(callBack : (any) -> ())
	local connection
	connection = self:Connect(function(...)
		callBack(...)
		connection:Disconnect()
	end)
end

function Signal:Wait()
	local thread = coroutine.running()
	self:Once(function(...)
		coroutine.resume(thread, ...)
	end)
	return coroutine.yield(thread)
end

function Connection:Disconnect()
	table.remove(self.signal.Connections, self.index)
end

return function() : Signal
	return setmetatable({
		Connections = {}
	}, Signal) :: any
end

1 Like

I noticed your :Wait() doesn’t use coroutine.resume and coroutine.yield which would be more efficient and less bloated. So I made one of my own using them if you’d like to take the :Wait() code for your own aswell.

--!strict
--> Signal Class
local Signal = {}
Signal.__index = Signal

--> Connection Class
local Connection = {}
Connection.__index = Connection

--> Types
export type Connection = {
	index : number,
	signal : Signal,

	Disconnect : (Connection) -> ()
}

export type Signal = {
	Connections : {[number] : (any) -> ()},

	Fire : (Signal, any) -> (),
	Connect : (Signal, callBack : (any) -> ()) -> Connection,
	Once : (Signal, callBack : (any) -> ()) -> (),
	Wait : (Signal, timeout : number) -> (),
}

--> Signal Methods
function Signal:Fire(...)
	for i, v in pairs(self.Connections) do
		v(...)
	end
end

function Signal:Connect(callBack : (any) -> ()) : Connection
	table.insert(self.Connections, callBack)
	local index : number? = table.find(self.Connections, callBack)
	
	return setmetatable({
		index = index,
		signal = self :: Signal
	}, Connection) :: any
end

function Signal:Once(callBack : (any) -> ())
	local connection
	connection = self:Connect(function(...)
		callBack(...)
		connection:Disconnect()
	end)
end

function Signal:Wait()
	local thread = coroutine.running()
	self:Once(function(...)
		coroutine.resume(thread, ...)
	end)
	return coroutine.yield(thread)
end

--> Connection Methods
function Connection:Disconnect()
	table.remove(self.signal.Connections, self.index)
end

--> return
return function() : Signal
	return setmetatable({
		Connections = {}
	}, Signal) :: any
end

Also, here’s an example of usage:

local signal = require(game:GetService('ReplicatedStorage').signal)

local testSignal = signal()

local testConnection = testSignal:Connect(function(number : number)
	print(number)
end)

testSignal:Once(function(number : number) --> prints '5' once
	print(number)
end)

testSignal:Fire(5) --> prints '5'

task.wait(5)

testConnection:Disconnect()

testSignal:Fire(10) --> doesn't print
3 Likes