My lightweight Signal module

Signal is a lightweight module to replace BindableEvents.
This is 6-7 times faster than ROBLOX’s events (~0.22s vs ~1.50s in for loop 1m iterations of Fire() calls)

Example of usage:

A.lua

local Signal = require(game:GetService("ReplicatedStorage"):WaitForChild("Signal"))
Signal.new("Test"):Connect(function(...)
	print(...)
end)

B.lua

local Signal = require(game:GetService("ReplicatedStorage"):WaitForChild("Signal"))
local MySignal = Signal.WaitForSignal("Test")

MySignal:Fire(1,2,3)

Github: GitHub - justqstn/RBLX_Signal

What makes this signal module superior to preexisting ones already on the DevForum?

Why is everyone making signal modules recently? I’ve seen maybe 3-4 in the past few weeks. GoodSignal has existed for years, there’s not much reason for people to switch from battle-tested existing modules like that…

3 Likes

idk lol just made it and dropped it here

idk rlly
just wanted to make post here

Because GoodSignal is very ironically NOT good…
Its dynamically typed :skull::pray: + slow.
Also people do them mainly becouse BindableEvent sucks a lot and a Defered signals made it 10 times worse

i think because it uses coroutines and task.spawn
i tried to call 1m coroutines and they’re not optimized as expected
but when i tried to use task.spawn… uh task.spawn is 10 times slower than coroutines, so i dont have idea why they use it. but i didnt try to go deeper, i just added :FireAsync()

also want to know wdym dynamically typed?

dynamically typed means that it doesnt work with
–!strict mode

…So do your module.
Also why does it uses --!native?
It will not make it any faster without static types

tried to use --!strict and got 16 warnings because i didnt use your method for OOP
image

also tested it in strict mode and it was a bit faster than in native (maybe its just an inaccuracy)
so ok i will fix all errors and if it will make any favor it will worth it

you can do static types in metatable OOP aswell but it is more complicated and you need to know how to do casting.
(code taken from Type checking - Luau)

local Account = {}
Account.__index = Account

type AccountData = {
    name: string,
    balance: number,
}

export type Account = typeof(setmetatable({} :: AccountData, Account))
-- or alternatively, in the new type solver...
-- export type Account = setmetatable<AccountData, typeof(Account)>


-- this return annotation is not required, but ensures that you cannot
-- accidentally make the constructor incompatible with the methods
function Account.new(name, balance): Account
    local self = {}
    self.name = name
    self.balance = balance

    return setmetatable(self, Account)
end

-- this annotation on `self` is the only _required_ annotation.
function Account.deposit(self: Account, credit)
    -- autocomplete on `self` works here!
    self.balance += credit
end

-- this annotation on `self` is the only _required_ annotation.
function Account.withdraw(self: Account, debit)
    -- autocomplete on `self` works here!
    self.balance -= debit
end

local account = Account.new("Hina", 500)
account:deposit(20) -- this still works, and we had autocomplete after hitting `:`!
2 Likes

this code looks like you’re making two types for one purpose
but there is no methods in type AccountData

why luau is not same as C or C++ :frowning_face:

1 Like

but i find it cool because there are comments of methods!
idk why i didnt made it later, im kinda stupid and lazy dude
tysm