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.
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.
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,
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
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.
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.
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
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.
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.
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.
Nothing too big changed, this update is backwards compatible.
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.
:Once now returns ScriptConnection.
Fixed type issue where no intellisense worked on Roblox’s Script Editor.
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.
Would like to add that it seems like FastSignal’s implementation seems to be just like Roblox’s :Once and so expect behaviour to be the same, if you think otherwise please bring it up over here (or well on GitHub, I’ll notice it faster there.)
What’s your reasoning for not re-using the same coroutine?
As far as I know the only “benefit” to doing so is all spawned threads being halted immediately / connections being disconnected when a script is removed if you use a new coroutine every time as with a simple task.spawn. In my experience almost everyone who wants to use a signal class wants to do it from a centralized system of modules where there are not script objects being created and destroyed anyways so that’s why I prefer the additional performance of reusing the coroutine.
Is that just in the name of matching the RBXScriptSignal behavior more closely or do you think that behavior is actually more desirable in practice?
I’m not sure why you thought I didn’t, but I do thread recycling on Immediate mode, not on Deferred because it doesn’t seem to be possible / doesn’t make sense. It also doesn’t happen in RBXScriptSignals on Deferred, but it does on Immediate.
The only thing that is different I believe from GoodSignal is how it recycles threads, I noticed the argument leak issue when first creating a coroutine before it was mencioned to you and I believe I updated my code to deal with that before, I’m not sure how you do it on GoodSignal since I haven’t really look at it for a while, but FastSignal should have some more cost when first firing and creating a thread to reuse than GoodSignal (at least when that was not patched) but should run the same way if no extra threads need to be created because a connection yielded for example.
This is one thing that I’ll never try to change for API parity, FastSignal tries to be as similar as it can, REASONABLY, to RBXScriptSignal behaviour, I wasn’t really aware of this, but things like disabling, destroying scripts is wrong enough to me to basically do anything for it to not matter to me, and I would never change my library for that much of a performance hit for the sake of something that is to me, deprecated ways of doing something.
Thread recycling has pretty big performance improvements even if its not just running the connection directly, which you can notice with a lot of connections running like you know, and while I usually am the person that would try to create completely unbiased libraries, disabling/enabling scripts is one of those things that even if a person isn’t using my library they will run into problems anyway, so I found that to honestly just not be important especially if it means losing the performance gains that Immediate has from thread recycling. (Which seems to be one of the biggest issues for people moving to Deferred when they relied on how Immediate performance logic worked)