FastSignal 10.2.1 - A consistent signal library

Hi! This is FastSignal.

It’s an alternative to GoodSignal, with type checking, documentation, etc, it takes a slightly different approach to things than GoodSignal.

This is not the same FastSignal advertised by stravant’s post! While being the same name, don’t let it fool you, it doesn’t sacrifice everything for performance. It prefers to be efficient, not speedy by all costs. It’s actually slower than GoodSignal but that’s because of some internal decisions which fix some other issues.

For example, here are some things that aren’t an issue with FastSignal, but would be with GoodSignal.

Issues with GoodSignal:

  • GoodSignal does not support .Connected.

  • GoodSignal has no :Destroy, only :DisconnectAll which means you can’t stop new connections from being created.

  • GoodSignal’s :DisconnectAll does not call :Disconnect on connections, this causes an inconsistency with RBXScriptSignals.

  • GoodSignal’s connections and linked list nodes are the same reference, which causes issues such as disconnected connections can leak the connection’s function, signal, and other connections if not cleared properly.

  • GoodSignal’s classes are strict, meaning you can index members that don’t exist, this is pretty useless, and means that empty fields in a class are false, and not nil, which is something that makes forking a bit harder and it takes a bit of time to process.

  • GoodSignal’s connections are not immediately compatible with Janitor, or Maid.

  • GoodSignal’s methods don’t have any type declaration at all, which would make it way nicer to use.

These things can of course be fixed with a fork like Knit’s, but the base version is not like that and it usually moves into the forked version as well.

Cons compared to GoodSignal:

  • :Disconnect is slightly loser in most occasions, however faster when has many other nodes in front of it, and can skip many table accesses. This is only the case when there’s only one connection and you’re trying to disconnect that, it’s not much slow and it’s still faster than RBXScriptSignals.

FastSignal specific features:

  • :Once which connects a handler, which can only be fired once. (Which was introduced first in FastSignal and then on sleitnick’s fork and then now on Roblox!)

  • An adaptive version, which can detect if your game uses Deferred or Immediate signal behaviour, and adapts to it.

And as you can notice above, FastSignal contains a Deferred mode as well!


Download :sparkles: GitHub

Documentation :open_book:


Plans


Report any bugs, unexpected behaviour if you find any, you can do that by submitting them using GitHub issues.

You can ask questions below replying to this topic, or submitting them on GitHub’s Q&A.

36 Likes

Could I use this on my plugin? It’s really cool.

  • BTW: I will give you credits :slight_smile:

You can use this library basically however you want to, it’s under the “Unlicense” license, you don’t need credit to do anything, and you can do basically anything you want to.

Edit: It was changed to the MIT License, but then again you can basically do whatever you want with it. I wouldn’t care.

1 Like

Release - 5.0.0 > 5.2.0

Only changes listed are changes from 5.2.0


An issue with G’Signal and that was an issue with this Signal library as well, as that having a reference to a connection, even if disconnected, leaks the function from it, and could even leak some other connections linked to it. Now disconnected connections’ hidden values are now properly cleaned.
This makes :Fire slightly slower, and :Disconnect can now allocate some memory to a table, in my opnion this is worth the trade-off.

Update 5.2.0 > 5.3.0


You can now use signal names like when they had them!

  • Signal:SetName
  • Signal:GetName
  • Added TOSTRING_ENABLED variable which decides if there is a :__tostring method.

Now when you print a Signal, it won’t print its private contents, but instead "Signal ".. SignalName! Same as Roblox’s ScriptSignals!


Calling Signal.new with a string will automatically set that Signal’s name to that string.

local Event = Signal.new("ClassUpdated")
Event:GetName() -->      "ClassUpdated"

These names are used for debugging, whenever you do something wrong with that signal, it will warn you, and will it warn you telling also which signal it is, using its name.

1 Like

Update

5.4.1 → 6.0.0


This update is pretty useful!
This update adds types to FastSignal, Signal.Event and Signal.Connection!
If you don’t use type checking, don’t worry. This still is useful.

Having types for both these classes, means that we get overall better auto complete, you don’t need to strictly specify it, but as you can see below, you get extremely rich auto-complete, even outside Roblox-LSP!

This puts it in-front of other Signal libraries in terms of ease of use, and also better similarity to RBXScriptSignals!

There have been also some silent updates since the last update post, but these are mostly internal changes which don’t change much of anything to anyone.

I’m new to type checking, and I only do it for simple stuff like these, if you see any issue or improvement, feel free to open a Pull Request on GitHub, or an issue to point it out.

1 Like

Update

? → 7.1.0

Changelog

  • Methods now have type notations! :partying_face:

  • Removed :ConnectParallel. I might add it back when we get an option to spawn a thread in parallel properly!

  • Added :ConnectOnce, a method which connects a method only once, it only runs on the next :Fire call. :cool:

  • Signal types are now, ScriptSignal.Class and ScriptSignal.ScriptConnection.

  • Added 3 new versions of FastSignal, Immediate, SimpleDeferred, and Adaptive.

These new versions are slightly different than the main release, which is called just Deferred, they don’t have a :__call metamethod, and don’t have some of the locals used for customizability, like not erroring on :Disconnect.

These are considered now the definitive versions of FastSignal, as they’re simpler.

Immediate is basically GoodSignal which proper .Connected support.
SimpleDeferred is basically Deferred but without the things listed above.

More notably, Adaptive is a version which adapts to your game’s current SignalBehavior setting. It uses some tricks to achieve that by using BindableEvents when FastSignal is first required, Note: Adaptive will yield when requiring it.

Adaptive is the most similar to RBXScriptSignal behaviour.


I was looking at teh github link and in the source code, there is a line of code that looks like this: handle: (…any) → (). What does this do, and what is this kind of syntax ?

That’s type checking!
I personally gathered the part of separating function types in two lines because I personally found it more readable / less cluttered,

image

Type checking is basically so that you can tell your script editor “this can only be this one type of thing”, and then it will warn you if you try to set it to a different thing, etc, there’s a lot in that area that does something similar.
In this case, that’s the syntax for a function, in this case this function can receive many many arguments, that’s undefined, but it doesn’t need to return anything.

(...any) are the args, -> () are what that function would return.

I personally type check some locals for possible performance gains in the future and for methods, so that you can look into what a method receives / returns directly from the script you’re requiring that library from, better auto-complete, it helps a lot, and is bound to be better and better with time.

I was the one who requested function types to suggest argument names on Roblox-LSP to Nightrains, but (...any) is a bit annoying as most times it just means you aren’t sure, I need to discuss that so we can see if I can get him to make that an exception :sweat_smile:

1 Like

Update

7.1.0 → 7.1.1

Changelog

  • FastSignal’s ScriptConnections are now compatible with Maid and Janitor, by having a .Destroy method which points to :Disconnect! Use :Disconnect, :Destroy on connections is just for compatibility with these libraries!

  • :Connect now has a explicitly return type of ScriptConnection.

1 Like

Thanks for the detailed response ! I will defiantly try to incorporate this ‘type’ concept in to my scripts, it sounds very interesting.

1 Like

Update

7.1.1 → 7.1.2 → 7.1.5

Changelog

  • Adaptive no longer yields when requiring it :tongue:

  • Reversed one of the changes in the last update to fix some possible? issues with types

  • Change thread recycling code to a different method which should fix a handler possibly memory leaking, (this isn’t any slower if none of your connections yield, it’s also more readable and understandable)

Note: I expect to completely remove the legacy FastSignal soon (probably on 8.X.X), aka Deferred, in order to replace the main one as Adaptive, and have Deferred be what SimpleDeferred is right now, have it and Immediate as other alternatives.


Is there any reasons why not use GoodSignal over this?

Is there a reason I should use your signals over the default signals? Are they more secure or faster?

Edit: nvm I misre

There are some on GitHub’s README file.

Update

7.1.5 → 7.1.6

Changelog

  • Added .Is to check if the object passed is a ScriptSignal
  • FastSignal is now on Wally as lucasmzreal/fastsignal! :partying_face:
  • Legacy versions of FastSignal were removed.

We now have Moonwave documentation! (It’s on testing, contributions are welcome)

Update - FastSignal is now stable! :tada:

7.1.6 → 10.0.0

Changelog

This is the beginning of the stable era for FastSignal! This will mean that FastSignal will take less risks with messing / removing features from the library.

FastSignal was deemed stable enough for this release. Any bugs, weird behaviour, must be reported immediately.

  • Fixed issue where :DisconnectAll wouldn’t actually disconnect connections
  • Finished moonwave documentation / comments
  • Immediate and Deferred now have a bigger separation, as they don’t any code that the other one needed to function properly
  • Optimized :DisconnectAll as well, so now it’s much faster
  • Adaptive now requires that Deferred and Immediate exist, it longer is a separate version, instead, it just requires the right one
  • Adaptive’s Signal now contains .Deferred and .Immediate which point to a specific mode

There are other smaller / forgotten changes.

It’s important that you update your copy of FastSignal. It fixes, as stated above, a typo, which could cause memory leak which was caused :Destroy / :DisconnectAll not disconnecting connections.

Note: Adaptive is going to be removed, Deferred is going to become the main version soon. This will happen when Deferred Events fully launch, and when it is no longer something you can choose anyway.

Note 2: FastSignal is now gonna follow SemVer for versioning.

Update

10.0.0 → 10.1.0

Users, please read:

So, this is embarrasing.
If you look into FastSignal’s changelogs, you would have noticed that :DisconnectAll was not actually disconnecting connections because of a typo. This happened again, with the same exact typo, except it’s not :DisconnectAll , it’s :Disconnect . While it wouldn’t fire those connections, the nodes were still there, so it was essentially leaking stuff. At least I caught it now.

Kinda embarrassing to say that right after saying FastSignal is stable, but yeah lol. This was probably a side effect of moving away from connections being one single reference, and me just not noticing it.

Anyway, yeah… Please update :) It’s pretty serious :/

Changelog

Other than that, there are some nice things :slight_smile:

  • FastSignal now has extremely specific, dedicated internal types, this will help debugging in the future, and also solves this issue on Studio, it causes some weird side-effects, but it doesn’t cause actual issues. This is really nice for intellisense.

  • Internal comparasions are now explicit.


I’m fairly certain this will be the last major update to FastSignal, I’m probably gonna have a silent update soon when Moonwave updates to simplify some things, but nothing too big, it’s just comment changes and so not worth announcing.

Hey, how did you make da event like

local sig = signal.new()

sig:Connect(function()

end)

I wanna know how you made the :Connect(function().

Update

10.1.0 → 10.2.1

Hello! Welcome back! It’s been some time! :blush:

Changes

Nothing too big changed, this update is backwards compatible.

  1. Roblox is now releasing a new RBXScriptSignal function which will be :Once, FastSignal already implemented a similar function which was :ConnectOnce which was then even added on sleitnick’s fork of GoodSignal. For API parity, it has been renamed to :Once, however you can still call :ConnectOnce.

  2. :Once now returns ScriptConnection.

  3. Fixed type issue where no intellisense worked on Roblox’s Script Editor.

  4. Moonwave page finally updated.


Important notice

Because :Once hasn’t actually launched, we also don’t know exactly how it works.
Because of that, if :Once behaviour is not the same as the one we expect by how it works and how it is implemented here, then its current implementation here, will then be moved to :ConnectOnce and :Once will by replaced by a Lua implementation of how it works on Roblox.