#Signal Certifications & Class-Grader
1 messages Β· Page 3 of 1
truly deferred is deferred
not just semi deferred
and I think best change is... if you want OG disconnect all then
Deferred disconnect nested connections + default disconnect current connections
oh no, I mightve realized a bug
calling the smae function twice would cause it to change to DISCONNECT_EVERYTHING
π
fixed that bug
So this?
β¨β¨β¨```lua
cn1 = signal:Connect(function()
cn2 = signal:Connect(fn)
signal:DisconnectNestedConnections("immediate")
signal:DisconnectNestedConnections("immediate")
print(cn2.Connected) -- false
end)
signal:Fire()
print(cn1.Connected) -- false !?
^ Will add this as a test if it is
yeah because I decided to think about it a bit
now it shouldn't happen
Thx π€
It is indeed fixed π
Haven't added any new tests, I only doubled up the method for [26] - [29]
guess now it's a waiting game for github
I think ill need to scrub the whole 6inch9inch identitify from that one lmao π
Also shouldve elaborated
thats when you want it deferred
it firstly go "ok ima clean nested connection" and then "ok ima clean everything"
hmmm, seems like im not using the entire potential of lastQueueClear, but ill that as is because I'd need extensive performance testing
or another suggestion would be to change the whole β¨β¨handleDisconnectAllStateβ©β© to a if check comparing if signal wants it gone or not lmao π
then you got everything in 1 iteration
Im gonna wager that option, but I should benchmark to see if it does make a difference
(I just batch every deferred job into 1 loop now, removed β¨β¨β¨_lastQueueClearβ©β©β© as it's kinda doing nothing, unless you are calling 2000 times β¨β¨β¨DisconnectAll / DisconnectNestedConnectionsβ©β©β© on the firing signal)
^ this is assuming the worst case scenario where you make 1000 signal objects with 10 connections before deferring DisconnectNestedConnections
the β¨disconnection aweβ© update is here
(fixed a small type error on old solver, my bad)
also shouldve mentioned that performance is the same outside of that
Peak optimization π£οΈ π₯
I mean another one could be that I only then have a queue with "valid" mutations, but I dont feel like it
Optimized connection insertion to the priority LinkedList π
- Removed the β¨β¨β¨β¨β¨β¨β¨β¨β¨
sideβ©β©β©β©β©β©β©β©β© variable & moved code so 1 less if-statement is used. - Added the β¨β¨β¨β¨β¨β¨β¨β¨β¨
usesPriorityβ©β©β©β©β©β©β©β©β© β¨β¨β¨β¨β¨β¨β¨β¨β¨(nil | true)β©β©β©β©β©β©β©β©β© flag for each signal, to simply insert new connections to the priority head if only the DEFAULT_PRIORITY has been used without any further logic or LinkedList checks.
^ Most of the changes are in the β¨β¨β¨β¨β¨putInPriorityβ©β©β©β©β© function
Before:
After:
^ Only affects β¨β¨Connectβ©β© & β¨β¨Onceβ©β© benchmarks, ignore Fire_ benchmarks
I say that and then add it
this shouldn't change "much", but it does remove useless mutations lol
Does this include the optimization I provided?
Gonna add it real quick
No, I did this seperately
(because I haven't seen what you did)
but ill implement that my own way if you want
Already added (I just copy-pasted the β¨β¨β¨putInPriorityβ©β©β© function I did & included the β¨β¨β¨_usesPriorityβ©β©β© type)
0.7 microseconds on manyyield, yikes...
It's about the same as before, perhaps it shines in an outlier test (thousands of connections)?
it should not
decided to implement your implementation but different if check + fixed some edge cases in my code lol
let me know if it's good
New speed:
Good on certifications & behaviors testing π
2 small if checks change
(still covers the edge case, just now more "clearly")
woah, can't believe we dedicated optimization updates now
yeeeeees yeeeees more more MORE!!!
guess slumber for another 3.5 years
I mean speed can be gained from inlining stuff, but I doubt I want to ruin readability lol............
OH wait... INLINE fire functions....
- Inlined fire functions (ie. I had β¨β¨β¨
signalFireβ©β©β© and β¨β¨β¨signalPriorityFireβ©β©β© function, but I put function contence into the class method directly), I thought it'd be neater to put them in seperate function but I guess not
Roughly the same as before but it's reliably slightly faster in β¨β¨Fire_OneYieldβ©β© now (no longer hitting 1.0 microseconds in 1 out of 4 tests)
I mean reduced overhead on that one
so I think it's OK now
^ ironically if it wasn't for priority connections then some things would've been faster
@scarlet pecan so I guess it should be ok to update now
ping me when update, thanks
it's already updated, shhhh
I wasn't sure if MaddestCat did it, but he did
this one?
Yeah, or you could check https://create.roblox.com/store/asset/121749520423997/SomeSignal as I didn't forget updating it
alrighty, thank you!
i'd fix the variable shadowing if i were you
for example you use "type" a lot
see how type is blue
I don't think you will ever see yourself using β¨β¨typeβ©β© in a signal inside of a method / function, only β¨β¨typeofβ©β© π
meh, it works so it works
fair enough
It's "hard" to avoid variable shadowing when you only want to convey the message (and not make it long) π
It now only refers to your creator store link (until you make the devforum or github page) π
^ No more update delays from my guide due to me being late
thank you
shouldve probably said what the "edge case" couldve been, basically you change priority of current connection (which is deferred), then you force disconnect current connection, and if you call :DisconnectNestedConnections(), change priority mutation gets excluded from transfer table
but I fixed that by just... not excluding it from the transfer table
that was my nichΓ© problem
Im guessing all is good? no issues with the signal?
Haven't used it in a real-situation yet, I'm still developing my own tools before I continue my projects (working on a successor to Janitor for more versatility rn)
The Signal Certifications Grader and Behaviors Tests are speculative of nearly all real situations I would use a Signal in though, no issues about SomeSignal on my end π
π
guess I really do need use this in my TD project to see if it can be used normally
lol
hell yea this time ordering doesnt matter because I can just assign priorities
Absolute peak feature ngl π₯
Built-in custom ordering will save me a lot of time
a successor to janitor? sign me up...
we need a #1017074018987290644 post on this...
I'll ping you once it's ready for release π
i love you π
I wonder what it will be so "successor" about it, customizable cleanup keywords?
Here's a demo if you would like to check it out, I've left most of the current documentation in the typing. Let me know if you have any questions, suggestions, or if anything is wrong. π
NOTE: IT'S NOT COMPLETE YET
To do tomorrow:
- β
Fix
:AssignToNewJanitor()'s bug- Also rename to
:MoveToJanitor()to be more implicitly accurate
- Also rename to
JanitorMeta:LinkToSignal(methodName: MethodName, signal: Signal, persist: boolean)- Links a specific method to the provided signal, allows for multiple signals & will disconnect all non-persisting connections upon cleaning up.
- MethodName is just the current method-strings of Janitor, most importantly being
CleanupAllorRemoveAll.
- Add more TypeCleanupMethods presets
- MadJanitor is already compatible with ANY input value for as long as it already has a preset or you can customize its
objectConfigs, presets are just for convenience (automatic cleanupMethod detection). - Promise preset
- Think of some more presets later
- MadJanitor is already compatible with ANY input value for as long as it already has a preset or you can customize its
- Misc. methods (easy but low-priority)
JanitorMeta:Destroy()ObjectMeta:SetForcedType()
- Actually do better type generics for
valuefor the sake of autofill... this is gonna be fun... π - Thoroughly test all methods in every niche situation I can think of
- It should already work for the most part after doing a few rough tests, but there may still be bugs.
- Also be on the look out for documentation inconsistencies, I had to revise a huge chunk of it twice so some parts I've forgotten to update may be outdated. π
- Benchmark & work on optimizations. Will do this last, only after I've confirmed everything to be working.
Documentation here:
@rough rivet if you want to check out the incomplete (but mostly working) demo
Here's some example code if you want to get a feel of how MadJanitor could be used (this doesn't include everything)
There's a bug with [object]:AssignToNewJanitor(), working on it tomorrow
you a winner (small fix on old type solver LOL π)
I'll check it out but not right now
Moved this to a new post for relevancy
https://ptb.discord.com/channels/909926338801061961/1469721975361507422
I was curious lol, but I now consider it somewhat useless though with how little the differences in speed actually matter unless you frequently use 10k+ connections.
If using less than that? I heavily prefer utility (SomeSignal) over human-imperceptible speed.
cant believe it that my signal almost can catch fastsignal
π
though I should probably refine SomeSignal function comments and then possibly make a forum post (without github link, it takes like 5 business days for a response)
https://devforum.roblox.com/t/namedsignal-β-name-and-define-variadic-parameters/4341837
something new came into town
Developer Forum | Roblox
A Luau signal implementation that lets you name and define variadic parameters β conveniently. a01: type begone! Download β Documentation β GitHub Signal = "nowoshire/namedsignal@^1.0.0" Requires New Luau Type Solver NamedSignal is built for the New Luau Type Solver, it is not compatible with the old solver. See Compatibility - Name...
get a move on ladies
also what's the point of making it compatible with the old type solver
fuck that
Oh cool... basically just a signal where YOU define the what the arg names are
I still believe new solver too raw
yeah
i think this would be nice in somesignal too
this would throw old type solver support, cough cough
ugh... stop crying and GET A MOVE ON
NOBODY CARES ABOUT THE OLD TYPE SOLVER!!
RAH!!!!
ill consider that once new solver is stable enough to migrate from old one
You'd care if you used... PACKET
it DOESNT WORK ON NEW SOLVER BECAUSE FUCK YOU!!!!!!
This will dethrone Zignal as the best class 2 signal as soon as they fix one bug in the Scheduler Certification (shouldn't run connections created mid-way through a fire) π₯
BLINK IS THE BETTER PACKET
My point stands, ill wait until new solver is stable enough
because it was half of a excuse to release in a ass state
π
i understand sir
it's okay i still love you
also https://github.com/Elentium/Wire should probably be added to the signal certifiactions thing
same with this maybe
we need ALL the signals on it
ironically how'd you benchmark this
because this doesn't return object, just data
(data orientated design)
Cannot be benched without changing the hardcoding in the Signal Certifications Grader (hundreds of lines), because you need to manually pass through an id (referencing the signal) when firing using Wire, here's the developer's thread for it: https://ptb.discord.com/channels/385151591524597761/1467425776616865896
I mean that's technically why it beats everything lmao
you just murdered the entire "overhead" for it not being OOP anymore
wait so... namedsignal is the... fastest most bestest most perfectest signal there ever is...?
oh me oh my...
We are talking about... wire
NamedSignal is just Zignal + SignalPlus hybrid in a dressed hat β€οΈ
RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGH
local WireController = require(script.Signal.Value)
local wireId = WireController.signal()
local function fn() end
WireController.connect(wireId, fn)
WireController.fire(wireId)
gotta require wire in every script/module which uses wireID
wire can do parallel luau aswell...
You could also store signals in a module with a key π
local SignalStorageMD = {}
local SignalArray = {}
local SignalDictionary = {}
SignalStorageMD.getSignal = function(signalId: any?)
return SignalDictionary[signalId] or SignalArray[signalId]
end
SignalStorageMD.addSignal = function(signal: Signal, signalId: any?)
if signalId then
SignalDictionary[signalId] = signal
else
table.insert(SignalArray, signal)
signalId = #SignalArray
end
return signal, signalId
end
return SignalStorageMD
my ass might have to switch to wire guys...
TRUE parallel β€οΈ
aww i thought it used actors under the hood
Wire is peak ? π€
fire must be called from within an actor to be able to use properly use parallel connections, the module doesn't come with any.
abusing docstring tags
Okay refreshed SomeSignal function comments + removed that 1 misleading comment line from CancelAllMutations
which is to say this if calling from signal B this method while signal A is firing, it defaults to immediate because it was before I fixed logic for that π
and the function comments just explain how it behaves, as function name should explain itself
Could you add version Ids to the module and maybe creator store description? π
So I & others could occasionally check if the current version we have is outdated or not, in-case we miss any announcements
Which is to say
I leave in the module the version and then on creatoe store you got some like "V2.2.7"
ye exactly π
^ Or maybe just the module because people can just open up its code anytime from the creator store page
Hm okay
im just gonna say that it expects you to know how to use actors
lul
ehhhh so lesse, V2 because we changed how connections are handled (no longer yields unless :Wait())
some x.4.x because it went through 4 "considerable" changes and then ehh... x.x.1 because function comment changes
V2.4.1 it is den
@scarlet pecan so this good?
Yee thx π€
now the hardest part will be writing the forum post lol........
or I could just... put that off for late-
because I dunno what i'd write that makes it stand out
that it passes all the tests your signal certification tests, lol?
It might be best to emphasize that developers will have true complete control of connection-dispatch timing while remaining synchronous to Fire unlike ANY OTHER Signal/BindableEvent, and also explain the extra features that your signal comes with (basically what my guide did).
Also provide a few code-examples showcasing what it would look like using it, to visually help the people who may be confused
I can get started on the SomeSignal explanation & tutorial video on Monday if you want to use that instead
π€
That might give me a idea on how to write that now
but it'd be mostly about it's behavior compared to basic BindableEvent/Signal
so to explain the whole deferred/immediate behavior, :Fire() yielding until it's done (synchronous)
defered and nondefered fire support?
We only got non-deferred :fire(), unless you were talking about how connections are handled
My guide explains part of it in detail:
https://devforum.roblox.com/t/signal-certifications-classes-guide/4263792/2?u=gohanducis
Connection mutations are optionally deferred in SomeSignal until after all synchronous connections are ran is what it means, all connections are ran immediately from start to finish by the time :Fire() returns (synchronous) for as long as the connections themselves don't become asynchronous (using a yield).
Example of synchronicity & asynchronicity:
local signal = SomeSignal.new()
local cn1 = signal:Connect(function()
-- Starts off as synchronous
print("wsg.")
end)
local cn2 = signal:Connect(function()
-- Starts off as synchronous
print("hi!")
-- Mutation deferral example
cn1:Disconnect() -- Mutation, this is deferred by default (until after all connections are ran, before :Fire() returns)
print(cn1.Connected) -- true
cn1:Disconnect("immediate") -- Mutation, this is forcefully immediate
print(cn1.Connected) -- false
-- Becomes asynchronous
task.wait(2)
print("hello!"
end)
-- ALL connections that
signal:Fire() -- "wsg.", "hi!"
print("bruh.") -- "bruh."
-- 2 seconds later...
-- "hello!"
--[[
Output:
"wsg."
"hi!"
"bruh."
"hello!"
]]
^ The Snapshot Certification should clear this up a bit
I only now realize that it's easier to do than explain lmao π
no what i meant was can u do :FireDefered() and Fire() where one uses task.spawn and other uses task.defer
i mean i personally dont have a reason to use task.spawn instead of defered but i can see some cases where ud need that
i also think doing
func() task.wait() end
to defer is worse than (not sure jus from memory of reading it somewhere)
task.defer()
task.defer forces all connections to be asynchronous, which isn't good if you expect logic like this:
local count = 0
signal:Connect(function() -- Using task.defer on this will defer this function to the end of the current CPU cycle.
count += 1
end)
signal:Fire()
print(count) -- 0, the connection wasn't ran before :Fire() returned which makes it asynchronous/annoying to work with if not intentional.
task.wait() -- Forces to wait 1 frame (at least 1 or millions of cycles)
print(count) -- 1
ye
i was just wondering if this module supported 2 types of firing
It's not built-in because it's quite easy to optionally do
task.defer(function()
signal:Fire()
end)
Similar to why most signals don't have parallel connections (also easy to optionally do)
cn = signal:Connect(function()
task.desynchronize
...
task.synchronize
end)
also is snapshot certification something that u want
idk if this is standard practice but this is something i usually do
if some state or condition isnt met i expect it to halt right away at the very tipy top and return
100%, it solves the primary issue in with mutations being forced to depend on connection-ordering.
Example with other signals:
local cn1, cn2
cn1 = signal:Connect(function()
cn2:Disconnect()
end)
cn2 = signal:Connect(function()
print("run?") -- This will never run because cn1 disconnected cn2.
end)
signal:Fire()
^ SomeSignal makes this optional without extra custom code on the developer's end.
-- Example with deferred mutations
local cn1, cn2
cn1 = signal:Connect(function()
cn2:Disconnect()
end)
cn2 = signal:Connect(function()
print("run!")
end)
signal:Fire() -- "run!"
-- Example with immediate mutations
local cn1, cn2
cn1 = signal:Connect(function()
cn2:Disconnect("immediate")
end)
cn2 = signal:Connect(function()
print("run!")
end)
signal:Fire() -- cn2 doesn't run.
--[[
Deferred mutations with existing connections are the default because of this logic:
"If I :Fire() this signal, I expect all connections to run no matter what unless I specify otherwise."
]]
Nested connections run in the next Fire using SomeSignal (under the logic that only the existing connections upon :Fire() will run)
SomeSignal example:
signal:Connect(function()
local nestedConnection = signal:Connect(function(fireId: number)
print("FireId: " .. fireId)
end)
signal:Fire(2) -- "FireId 2", reentrant Fires will wait for all connections to run & mutations to be processed before starting, these will also finish before the "parent" :Fire() returns.
signal:Fire(3) -- "FireId 3", consecutive reentrant Fires are also supported
end)
signal:Fire(1)
print("--------") -- Proof that nested/reentrant Fires are also synchronous
signal:Fire(4) -- "FireId 4"
--[[
OUTPUT:
"FireId 2"
"FireId 3"
"--------"
"FireId 4"
]]
@twilit fern Here's nearly every usage-example possible with SomeSignal (including extra features) if you're interested:
Most of it is @stuck thorn's work, I only provided the initial guide & assisted with logic + a few bug fixes πͺ
it does make you crazy though
Although it did make the previous & this month special
wildest update of them all... 2.4.1.1
- fixed one of the comments line position (its for the devs who want to learn from the code), I was drunk a bit
That says enough about Blink π
The creator acknowledges that it sucks so much it needs a complete remake. π€·ββοΈ
even if it sucked before the rewrite it STILL BEAT ALL Y'ALL
Yea it beat us in being ugly.
it beat you in being the best, fastest most lovable networking module there is
I'm so proud of blink
that's my boy π₯Ή
How dare you assume its gender in 2026!?
How did this turn into network library beef
*gendered network library beef
OMG I'M SORRY
i'm sorry blink
i've failed you as a parent
you're still the best networking library there is though
π
Gah damn, code has genders?
Well then, SomeSignal is not/it
i got lost a bit
@scarlet pecan are you gonna troll the next class 3 signal guy by adding "multi-signal behavior" certification?
π₯
Though I do see that I add unnecessary change priority for nested connection (which early returns anyway lmao)
I lowkey forgot to include that in the snapshot certification lmao, poor dude is gonna find out π
JUST BECAUSE I MENTIONED THAT YOU'RE GONNA TORTURE THE GUY
GOOD GRIEF LOL
guess we do really having 2.4.1.2 update (automatically assuming itll pass behavior test because I pin pointed the main issue)
that "fix" exists in disconnect, mostly oversight on my part π
let me know when its added
Will do, but your signal will pass it anyways lol (it's already in the behaviors test)
I know
Literally rigged battle from the start π
@scarlet pecan Also I think I know what NamedSignal owner talking about
Because its current is behavior equivalent of V1 of SomeSignal, connecting/disconnecting while signal is firing yields the thread
oh thx, I'll include that as a 2nd thing in my reply
Added π
Is it right?
Should be right
Just that this does it in reentrancy levels
you get reentrancy levels from :Fire()
and it's published, and some words rephrased on comments
Hmmm, I left oversight in SomeSignal somewhere
^ this was the oversight
small fix later :
the pin pointed issue was that I checked if state is nil, while in actuality I should have not, as above if statement did block it from transfering over + current connections are disconnected before this check
This marks the 2.4.2.2 update, to indicate what changes were made, I will now give short summary on creator store
@rough rivet you might like this update
MMMMMMMMMM
@scarlet pecan I kinda find it weird
OHHH IM STUPID LOL
π
I forgot that :Fire() while signal is firing yields the thread
Lowkey, do you want to add [signal]:ImmediateFire(...: any?)?
Going full circle with this π
what even is that
A nested/reentrant Fire that doesn't wait for all connections to run + mutation processing, it just Fires immediately
It WILL break some deferred behaviors if used incorrectly, but it might be good for the test you were trying to do
h-hell naw!! π£οΈ
we all truly know the remedy for this issue
task.spawn(Signal.Fire, Signal, ...)
also im making a post about this, because I doubt it fits to comment every change here lmao
official SomeSignal announcement at last !?
No dev forum yet, bwomp.
@scarlet pecan I think I got the craziest fix for tis...
if signal firing then task spawn a new thread <- althought it'd make fires not synchronous anymore
so ehhh, it'll be the dev job to decide if to yield or not
I like how majority of the features are just "do it yourself"
utility versatility at its finest π£οΈ π₯
yeah lol
I have zignal that is converted from oop
its so easy to convert really just consumes very little extra memory
but it is worth it
I think ill do with SomeSignal, mostly for consistency purposes
(Connection object doesnt use __index metamethod lmao)
@scarlet pecan out there exposing bad signal behavior keep up bro
Ive had my fair share on fast signal
Bc there were no unit tests showing how bad it is
My legacy code literally had to be trashed bc of that
W
W, this paid off lmao
Gonna update the Signal Grader today, upcoming features:
- β
Support for signals that internally don't use threads at all for
Connect&Once- tbh, I think it's a VERY good idea to optionally (not default Fire & certainly not the only option) have a Fire without asynchronicity safety. Because it blows BindableEvents right out of the water in speed for the
Fire_OneandFire_Manytests specifically (NOTFire_OneYield&Fire_ManyYield).
- tbh, I think it's a VERY good idea to optionally (not default Fire & certainly not the only option) have a Fire without asynchronicity safety. Because it blows BindableEvents right out of the water in speed for the
- β Tests for multi-signal usage
- β Tests for consecutive reentrant Fires (proven edge-case of a signal's internal design)
- β PCall test (to ensure Fires won't interrupt/break on a specific connection with an error)
Is this gonna kill NamedSignal
No clue until I finish (just taking a break eating breakfast rn)
I mostly meant the multi-signal usage as yk
This
executing functions in an order without pcall is highly dangerous tho
it will break if any of the subsequent functions errored
and wont run other stuff
1 bug leading to many bugs
We all know if that happens then it's programmers issue
you can't make sure nothing will error in a live game
it's so hard to predict that
imagine CharacterAdded failing because somehow Insert service fails
So we asking for promise execution
yes π€
Also what can fail with insert service
I mean I always try to keep the code as clean as possible use strict mode for practically everything
even after then
in live games
there might be stuff you missed
you don't want the game to just shit itself
if there's any errors
Yeah we have a tool for that: promises
return pcall(function()
end)
in the module loader ahh
unironically
Ive seen this
deadass
You can't ever be sure
Like I'm not dead-ass about it, TDS has that issue
It'll be loading controllers and then it stops because it got hit by a error
Good Lord LOL
Tis why you see signals task spawn stuff
π
oh god
So that's errors beyond control for ya
Good point, should I include that as a test in the Scheduler Certification? Specifically for signals that don't use threads for Connect & Once in their primary Fire, this test would only be done for ZeroSignal & CuteSignal
it should be a seperate category
Ironically I was joking about it because you code something wrong in the Temple OS and the whole OS would eject itself
I'll still have it as a part of the Scheduler certification, because the purpose I've given the cert is to guarantee basic functionality which includes being able to correctly execute all connections without weird bugs or interruptions, the latter I feel should account for pcalls that prevent Fires from breaking on specific connections that have errors
Rest in peace
jk, here it is:
CHANGELOG
- Scheduler Certification Changes
- New test:
AsyncErrorCatch, if signals that don't use threads forConnect&Onceconnections use pcall or xpcall instead for safe asynchronous error catching. - New test:
ConsecutiveReentrancy, if a signal can do reentrant Fire in the same Fire layer, as well as reentrant Fire in multiple reentrant layers. - New test:
MultiSignalCNs, tests if created connections are bound strictly to their signal in creation & to Fire. - New test:
MultiSignalNested, an expansion of the previous test but for nested connections. Also tests if one signal can Fire other signals within its connections (nested but not reentrant Fire). - New test:
MultiSignalDisconnectAll, ifDisconnectAllonly affects the signal it's used on.
- New test:
- Misc Changes
- Now supports signals that internally don't use threads at all for
Connect&Oncewithin the primary:Fire()method, which also reflects the speed benefits in the Speed Certification'sFire_OneandFire_Manybenchmarks.
- Now supports signals that internally don't use threads at all for
CuteSignal failed the AsyncErrorCatch & ConsecutiveReentrancy tests
Hold on I forgot to remove connection-ordering dependency for ConsecutiveReentrancy
Publishing to the devforum now
Is this fire
Indeed, 1 signal has been bumped down to Class 0 so far thanks to the new tests, FastSignal (I'm still retesting all signals)
DProSignal's Wait_Safety randomly broke on its own though
I don't think ill change much, other than pointing out signal with bugs
Gonna visually fix the baseline for MultiSignalCNs though (because it visually behaves more like a result than baseline)
nah bro it couldn't
1/2 billion chance that a stray atom hit your pc and it changed code of DProSignal
nvm FastSignal is actually fine
Changes:
- Fixed the Baseline insertion algorithm for
MultiSignalCNs&MultiSignalNested - Fixed support for asynchronous Fires in the new tests (FastSignal confirmed it)
Sending the fixed grader in a sec after I test other signals
you rn :
Updating the devforum fr this time (retesting all signals)
I was expecting bloodshed, but this good news atleast
okay final hotfix FR* this time trust, it's now more obvious if a value doesn't pass through in MultiSignalCNs & MultiSignalNested (so they're not mistaken for a false negative)
It still fails on a fresh untouched download of DPro & studio restart π
Updated the devforum π
Imagine π
It's thankfully all good now though lol
Retested CuteSignal, it's just missing pcall/xpcalls in its Connect & Once connections and then it'll be Class 1
Check out the Fire_One and Fire_Many speeds though, that's 3-4 times faster than other fastest signals that wrap connections in threads only (granted, they aren't wrapped in a pcall/xpcall yet) π₯
Who could have known such a revelation! π₯
Would it be possible to add optional SyncFire methods to SomeSignal so devs that don't use yields at all in their connections could take advantage of the speed? (Practically useless in nearly all cases except heavy simulation workloads)
signal:Fire()
signal:PriorityFire()
signal:SyncFire()
signal:SyncPriorityFire()
I did wager that option, but I haven't seen any performance difference
linked list is making the iteration FAT
task.spawn takes up about 0.3ΞΌs in benchmarks & is the reason why most signals aren't faster then BindableEvents in Fire speeds (on my device*) π
in my computer 1 connection makes this 1 small thing take ~10ΞΌs
(also how'd it work, fires do yield so you'd need to be wary...)
Wait connection yields are still fine dw (CuteSignal proved that)
Reentrant Fires should be fine too since they're functionally similar ^
Instead of thread recycling, it just wraps the connection's function in a pcall/xpcall
xpcall which just redirects to warn
π₯
although, I think it'd be nice to warn the user atleast if one thing fails in a pcall
HELL YEA LOL
xpcall returns a result from the 1st function if there's no error, otherwise returns from the 2nd function
-- Example 1
local success, result = xpcall(function()
local sum = "fifty" + 2
return sum
end, debug.traceback)
if success then
print(result)
else
error(result) -- Error + traceback
end
-- Example 2
local success, result = xpcall(function()
local sum = 50 + 2
return sum
end, debug.traceback)
if success then
print(result) -- 52
else
error(result)
end
-- Example 3
local success, result = xpcall(function()
local sum = "fifty" + 2
return sum
end, function() return "Do you have less braincells than the NUMBER you tried adding to the WORD STRING...?" end)
if success then
print(result)
else
warn(result) -- "Do you have less braincells than the NUMBER you tried adding to the WORD STRING...?"
end
IM RUNNING 10K VOID CONNECTIONS WITH SYNC FIRE
π€
like it only expects boolean while what it should return is boolean and R...
basically to show xpcall (the err function being the warn) in action
@scarlet pecan give it a go
(I just copy and pasted the fire functions)
actually I forgot 1 thing
dang
also, this doesn't make much different if you have 1 connection, it pays off when you get 100+ connections
while most pleasing is when you get 10k connections, then it runs at 60 fps for me
actually damn, I realized this bumps the ceiling a lot higher (50k connections and still 60 fps, although all frame budget went to iterating allat)
@scarlet pecan
after that it stopped, now I know why
what a screaming beast
I misunderstood you initially mb lol, my reading comprehension is drained as hell after the devforum π
Before:
Oh I gotta reword the errors (it did pass the AsyncErrorCatch test dw)
It froze on theConsecutiveReentrancy though
ironically the reason being syncfire does fire enqueue thing
so you'd need to conviniently wrap that in task.spawn... (trust me bro, this will be the SomeSignal META)
RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGH
is it okay, or should I change the behavior?
As long as it's able to do reentrancy on SyncFire / SyncPriorityFire π (because the issue is that it's indefinitely yielding rn)
mein gott...
(this will require entire removal of enqueue from the start, so uhhh... have fun!!!!)
but then the basic fire will get in the way lmao
oh yeah there's that too, multi-Fire edge cases...
this was suppose to be META... task.spawning SYNCFIRE would make this BLAZE GRASS
I think that would be fine tbh, wrap it internally π
HEHEHEHEHEHE
π£οΈ π₯
nvm I'm stupid, I forgot to pass the signal π€¦ββοΈ
I got a better idea
wsp?
Wrapping it in a thread will cancel-out its speed benefit for Fire_One anyways π
I think I made it mad
atleast it doesn't yield the thread now
it just throws C stack overflows
Getting somewhere π₯
It accounts for asynchronicity too π (the task.wait()s)
that's why
oh?
like I don't wait for fire in syncfire, it just goes
that's why you get 0 and then 2
because it's async
if I say that right...
I get it, but I don't understand much on why the Handler_Result connection wouldn't run
Is it being overwritten or skipped because of the asynchronous reentrant fires?
other than that, it works
oh neat π₯
im basically doing this in syncfire
we just assign a different thread to enqueue to the fire queue
lmao
I am not fixing that (You void reliability with SyncFire)
actually fixed it, just removed that it respects if signal is firing
@scarlet pecan
just that using Fire inside SyncFire will yield SyncFire thread
you is welcome
1 single minute to reverse that LMAO
I wanted SyncFire to respect signal firing, but that's like asking unreliableremote to be reliable
it won't be π
I have the right version right-?
Only modification I did to test SyncFire in the Grader (if that broke anything)
oh hell nah, that changepriority gonna fuck up so syncpriority fire so much LOL
Indeed π
I guess that's a given with immediate-only synchronicity lol, developers are on their on at that point if they choose to use SyncPriorityFire despite that
yeah okay, it ate crap in snapshot behavior, as expected of course
ironically, it does make this very fast
@scarlet pecan so now it should be OK
gah damn I realized what blunder can happened with you disconnect the last connection
π
Some mutations should still safely be kept even with immediate synchronous connections π
because I stop at last connection, BUT you can guess what will happen when you disconnect that ""last"" connection
it'll still keep going lmao
like im not joking this is where going from newest to oldest would benefit π€
actually that pisses me off ngl
The problem is just reversed if you do that π
It can be solved if you reimplement the mutation queue
oh wait then that loops right back to the reentrancy problem
What if...
You process mutations at the START of the Fire only if it's a reentrant Fire?
And then if it's the main/original Fire it does it at the end instead
fixed
oh wait that still doesn't solve it, it would only be a partial solution because it won't be able to account for "future mutations" of the reentrant Fire's Parent Fire... (referring to my msg above)
GUH!?
ofc this might have performance impact if you disconnectall lmao
Let's see how bad the damages are π
(might still be acceptable)
patched that out, MUAHAHAHAHAHA
I hope this would be the last, cause I want to sleep and maybe tomorrow release that as a "update"
also I shouldn't be worrying about mutations (or the snapshot behavior) on SyncFire, that's quite literlaly if you want it RIGHT NOW and don't want to wait for mutations
That's the cope talking...
But yeah I agree honestly
I mean I could probably make some changes to make this work and pass snapshot behavior, although that'd be very much just work
I lowkey think this genuinely might be impossible to solve because of logic timing, resulting in a catch-22 loop that urges reentrant Fires to become deferred again
The best that could be done is processing mutations at the start of the reentrant Fire, and remaining mutations of the og Fire at the end (after all connections are ran). This isn't a 100% solution because the reentrant Fire mutation-processing won't account for future deferred mutations of the og Fire...
All roads lead back to queues...
yeah, so ill keep as is
let it be ugly, but tasteful
so I guess it should be okay to release
but how would I demostrate how to be used
actually I don't have to, that can just be a update log with mention of said ting...
2 use-cases I can think of (if you still wanted to):
- Very fast data change receives & process-triggering for individual objects on a massive scale, think of NPCs (1k+ of them each with their own value-changed event) or projectiles (10k+ at once in one event)
- This HEAVILY benefits from not needing to create threads (they're the most expensive part of Firing) so there's a LOT more CPU processing room.
- Could be used to trigger something in stages (one connection per stage of the process), think of an ability usage in battlegrounds-related games. But I feel like this falls into the boilerplate category, this can easily be achieved using a single connection.
I hate he would be right if it wasn't for the fact that arrays are a bit difficult to deal with if you attempted to convert SomeSignal to an array-based signal π
oh you meant that, yeah lol
"I wish I was high on pot nuse" ahh signal π
SomeSignal is a abomination due to 2 additonal fire methods
Although it's probably best to transfer this to #1471192412696088688
Sounds good
Even if I'm going to sleep in a bit
idc if he's a lil special with those 2 extra chromomethods, he's still my boy I support π€
I mean like, it's got a little bit of this and a little bit of that, lmao
anything can be achieved in a single connection
source: trust me bro
π
π
LMFAO
bro thinks code does not have standards
this aint subjective gng π
who needs unit tests, I say it'll pass flawlessly by my judgement
yeah obv everyone just writes code
they never do verifying
never test special cases
every code to their own beauty πΉ
I curse my signals SyncFire just because you need to write spicy code for it (it's for oldest -> newest fire order)
πΉ
@proven yoke beauty of it's own
actually dang, I could've used return for this COUGH COUGH
tank you DrSienk for pointing out my coding beauty
DrSanky
PatientSand
binchqinch
SinukudePh
sounds like my stage name
π
Bro folded under zero pressure π
@scarlet pecan wait for the signal tests i assume you update each signal and check if they have --!optimize 2 beforehand right?
For live-server accurate performance yup π
There wasn't a noticeable difference in the Speed Certification tests though π
as expected tbh --!optimize is more about clever stuff rather than boosting it all up
Optimize is cleaning up my bloat
CHANGELOG
- Misc Changes
- The grader no longer gets stuck on a few indefinite yield cases (regarding
Wait_Safety&Wait_Chainedtests) and C stack overflow errors (ConsecutiveReentrancytest).- Meaning? Extremely bugged signals such as ZeroSignal can now run the Signal Grader to completion.
- The grader no longer gets stuck on a few indefinite yield cases (regarding
I guess it wasn't lying, it is indeed SPEED (lie)
bro failed everything
except speed
that's why he said that it doesn't fit in the leagues
it ate all the speed
The creator of ZeroSignal strikes again with a new signal... But this time it's ACTUALLY GOOD π£οΈπ₯π₯π₯
https://devforum.roblox.com/t/flow-signal-advanced-signal-library/4413930
Developer Forum | Roblox
Flow Signal Zero Signal continue with better perfomance and safety Library for Luau with DOD design Github Repo | Creator Store β‘ Speed. Simplicity. Next-Gen Flow Signall is a signal implementation for high-perf systems. Flow Signal designed by professional who knows that bad Signal libraries are evil Its fast, reliable and easy to use. ...
It does not use metatables
I guess that's the reason it's fast
Also, I didn't get their NULL thing
I benchmarked it and the difference is negligible and requires huge amount of iterations in order to see it
Just an another micro optimization...
Also, the author's and Yarik's nicknames are both russian so I guess they're friends
Or it's just a coincidence
I don't get the whole NULL thing
If you want null thing then you should've made a empty buffer (though doubt that'd change anything)
I really don't understand it
I bet it's fast because it does not use metatables
And, perhaps, SOA
I don't know about SOA, but no metatable does make a difference
SOA means table for each data. Not everything in 1 table
Kind of ECS
But simpler
I know that
π
Oh...
I just don't know if it does make a difference
I guess, it does make a difference if you have 5k+ signals
That's like flattening the data, then just doing for i = 1, len, step do
I don't think someone will have 5k+ signals
I used that for SomeSignal mutation queue, even if it doesn't add much
Just 1 less thing to iterate through
You never know
That reward is going to roblox itself lmao, everything has rbxscriptsignal
i like going to the somesignal devforum post or the signal certifications one and just reading the comments
this much beef over signal modules π
fr lmao π
"Yay another signal module which nobody will use!"
Anyways, another signal got released π
https://devforum.roblox.com/t/funcsignal-an-eventsignal-handler-native-fast/4415397?u=gohanducis
Developer Forum | Roblox
FuncSignal is a production-grade event system for Luau, benchmarked at over 8x faster than BindableEvents for primitives and up to 26,000x faster for complex data. Version 2.0.0 introduces Parallel Execution, Connection Pooling, and advanced Fire Filtering. Best For (OOP/Modules) That Return events where an event is needed. Easy Usage: local ...
testing it rn
All of them lead back to goodsignal.
LOL π
It didn't even occur to me that it was possible to pass in Connect_Safety but NOT general Connect functionality...
I mean... you do test 1 connection
Makes sense
had it been 2, it'd probably fail
what a gem source code
This guy knows how to optimize, unlike yarik
https://create.roblox.com/store/asset/165361891/Signal-Module?externalSource=www&assetType=Model
first signal module ever created i think
2014 from stravant
Absolute elite ball knowledge, the earliest I could find that was a definitive signal was from 2018 π₯
please test it i want to know how bad / good it is
let's see if it stands the test of time π
this walked, so GoodSignal could run
this is actually true
stravant made goodsignal too so
LOL
I'll have to make an adapter for it, it doesn't have Once nor DisconnectAll π
it's so good it doesn't even need them...
If you check the code, then it's just a wrapper for BindableEvent
can't you just pass in empty functions for once and disconnectall
or check if those methods even exist in the first place π
BindableEvent but with removed features π
https://devforum.roblox.com/t/tables-sent-through-bindable-lose-data/8177
this is the original devforum post
Developer Forum | Roblox
Iβve been noticing this strange behavior for a long time. In summary, when you send a table from one script to another, the hexadecimal address changes and sometimes data (such as methods in a table-powered OOP) is lost. I consider this bug fairly critical, as itβs currently hampering all my attempts to create a good object-oriented system ...
pretty sure that's why it's just a bindable wrapper
wow im failing the stravants signal test, my signal SUCKS... I should return to GOODSIGNAL.....
GitHub
Contribute to AlternativeLua/SuphisSignalModule development by creating an account on GitHub.
what the freak
Makes sense, it still can't pass metatable data through π
Am I gonna get crucified if I test this...?
you should rig the results
zignal*
Given up on making an adapter for this too, I pretty much need to rewrite it entirely if I want DisconnectAll to work on Wait connections and still have a working signal afterwards lol
ermm actually
if it wasn't for GoodSignal, there would be no Zignal
βΉοΈ
aww
I actually wonder if this did worse than Zero Signal
because that would be wild
SuphiSignal would be Class 1 if it fixed one issue with Connect_Safety (not run connections created midway through a Fire)
don't let suphi know about this π€«
i wonder, is it even possible to not be speed certified?
Lowkey, I think it did π
It's pretty much a freebie if your Signal works at all lmao, the only way it'll fail that is if it does something on the level of war crimes (NEVER program again if you fail this)
Guess SomeSignal doing war crimes (it sometimes failing at many_yield)
guess tas teh cost of mutation queue (because roblox no give a optimized queue)
actually that does make me wonder, had I proposed a fix for signal+, it'd actually not be in class 0 lmao π
i'll start adding while true loops to other signal modules and redistributing them to people
destroying reputations 1 while loop at a time
π
LOL NVM (I done screwed something up)
awesome
after the ""fix""
actually lol, if it was changed a bit more then it climbs to class 2
Signal powercreep goes hard π₯
What are the before/after speed benchmarks?
Didn't bother benchmarking
you can try the base SignalPlus with this though
thx π
Before:
After:
2 class bump and no changes in speed π₯
this debt comes at the cost of needing to scroll to find the end if something happens
truly
this is from ffrostfall
i'd test it
also this link is invalid
i get a 404 error
I love Roblox automod π
I included a file download below that link just-in-case of that exact situation lol
AI strikes again
wait bro
that was the issue
literally
can you test the signal under the Packet
Im like %99 sure I had a weird behavior with it
welcome to the winners club gng
this means you won
What was the weird behavior?
Aaaaaaand it's gone π₯
Poor dude got cyber-bullied to the point a mod had to remove it π
βΉοΈ
If it doesn't show up in tests then its probably fine
But vaguely I remember it was due to :Wait
I bothered testing, but it seems like it's okay
ππ
I will never know what happened back then
Actually wait...
lol fair, because it does task.defer
(I chucked my own DisconnectAll just so it no cry about it
this is technically snapshot certified, but at what cost...
I dont get it
Just because it's like Roblox signal behavior (deferred)
so obviously if you fire 2 fires in quick succession, that :Wait() will take 1 fire and ditch other
ARRRGHHH
that could've been weird behavior with :Wait()
lmao
bro
I think that's it
that was what I was encountering
Appeal accepted... in under a single business day !?
Insane
check this out
i don't think i sent this before?
it's from here
you guys should see if it's any good
It's basically a signal with :Connect() and nothing else, not even built-in asynchronicity support (thread usage) nor asynchronous error catching either π
local CreateSignal = require(createSignal)
local signal = CreateSignal()
local cn = signal:subscribe(fn)
cn:unsubscribe()
-- ^ that's EVERYTHING
oh wait yeah i'm looking at the source now and that's literally what it is
as simple as it gets basically
aside from the strict typechecking
bro removed the 2nd reason (there was none) π
yeah lol
yeah that's literally what it was
i couldn't even think of anything else
i guess the fact it's split up into multiple modules
for some reason
wow it even has a whole ass types module
INCREDIBLE!
It does make development of module better, but it must have a reason
^ ie. network lib benefits from it as it's just multiple components
This is 1:1 LemonSignal π
π€
@night tartan
balright
RAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
oh LOL
I'M SORRY
to make up for it here's my signal module which is like really fast
return Instance.new('BindableEvent')
you should try this lol
Yeah lmao
Class 3 when used correctly, this is legit a strong rival of SomeSignal, better & worse in some areas.
What I like:
:Fire()determines whether or not it should be completely Synchronous or respect each connection's synchronicity (faster on average than an Async-only Fire).:OnceTimeout()&:OnceAsyncTimeout()seems like it could have its uses, basically a:Wait()but for an input function instead of a thread.- Has ordered priority
Small issues:
- LITTLE TO NO TOOLTIPS NOR DOCUMENTATION. A few types are broken too due to typesolver updates I bet.
- POSSIBLE BUG: Signals created via
.all()don't self-destroy or reset their tracking after all of its input signals run, so they're effectively minor memory leaks after they fulfill their purpose if you forget to disconnect them. - There's quite a few boilerplate/unnecessary functions
:FireDeferred(), this is literally atask.deferwrapper with nothing new added...:ConnectIf&:ConnectIfAsyncare misleading, they don't perform the check before creating the connection like their names imply, they do it whenever the connection runs.:WaitPriority(), nearly identical to:Wait()except it removes the one condition check for timeouts, unnecessary micro-optimization tbh.
- Uses
coroutine.resumefor async connections, this may lead to hidden/hard-to-debug niche issues due to the engine.
I haven't done a deep dive into testing niche stuff like multiple signal nested usage yet, so I'm likely missing a bit of info & cannot guarantee yet if it's safe to use in all use-cases
#chat message
Honestly I would like to believe this signal was helped with AI lul
rahhhh who cares about security....... WE NEED SPEEDDDDDDDDDDDDDDDDDDDDDD
ngl...
LOL
No sane dev who uses --!strict would allow ts π
chat he might be onto something
I was like "is this a named signal copy" just becaues of the type functions, but I think not
Wait lemme compare them real quick mb
Completely different programming styles & greatly different signal structures, all good π
something doesn't compute here, some type functions are creepingly familiar
They do share the same usage of read & <Signature> in typing, but the similarities end there
The signal structures are still very different
fair enough
I was gonna ask, if this on the new type solver or the old one
π€
@proven yoke
New type solver probably, I can't find it in beta features anymore
Is it different for you?
it's not a beta feature anymore
you can find the solver settings in workspace
(although by default, it's new type solver)
Yup π
damn bruh
what even is class3
why does it have ordered priority
who wants that
#1453290240641859604 message
I know π
still confused about why
This was made out of spite, because roblox bindables are literally behind lol π
^ so is majority of roblox luau signals
bruh π
why does vesignal even have that then
what was his motivation to make it class3
Class 3 tldr:
- Connections are ran from Oldest -> Newest
- Everything that's meant to be synchronous in a connection is actually synchronous (run to completion), this needs to include nested Firing if the ran connection is still synchronous.
- Connection mutations are optionally applied only after all connections are ran, so disconnections are no longer completely dependent on connection-ordering. Do note that the code within connections are still order-dependent.
Incorrect ordering & mandatory order dependency of Bindables/RBXScriptSignals in general π
π
so this is only to replicate bindable behavior fully
Pretty much, except with fixed & improved behaviors (regarding ordering)
Bindables do Newest -> Oldest & disconnections always happen immediately, Class 3 signals do Oldest -> Newest and disconnections are optionally after all current connections are ran in a Fire
very interesting
Ive never had a use case for it but Ig its a thing
Yee it's not necessary but it's convenient
bruh I see
Oh and probably has no documentation because you aren't mean to use it