Skip to content

Defer disconnecting connections in signal:Destroy() to reflect native RBXScriptSignal behavior + Trove type improvements#249

Open
PolarisStarSystem wants to merge 7 commits intoSleitnick:mainfrom
PolarisStarSystem:main
Open

Defer disconnecting connections in signal:Destroy() to reflect native RBXScriptSignal behavior + Trove type improvements#249
PolarisStarSystem wants to merge 7 commits intoSleitnick:mainfrom
PolarisStarSystem:main

Conversation

@PolarisStarSystem
Copy link

modules/signal/init.luau

  • Defer disconnecting connections in signal:Destroy(), so that any calls to signal:FireDeferred(...) during the same resumption cycle but before the signal:Destroy() call will fire to the connections.

  • _proxyHandler disconnection is deferred with the rest of the connections.

  • This reflects native Roblox behavior when calling rbxScriptSignal:Fire(...) and then destroying a parent Instance, which still fires to its connections even with workspace.SignalBehavior set to Deferred.

  • These changes bring back old behavior as outlined in Cancel waiting threads if signal disconnects all connections #164 (comment), but only when signal:Destroy() is used instead. signal:DisconnectAll() retains its current behavior.

  • Move signal:DisconnectAll() behavior to new function called disconnectSignalConnectionsStartingFromItem and removed references to _handlerListHead in the new function. _handlerListHead is cleared immediately and sent to the new function from both signal:DisconnectAll() and signal:Destroy() instead.

  • connection:Disconnect() is unchanged as calling rbxScriptSignal:Fire(...) and then rbxScriptConnection:Disconnect() does not fire to the rbxScriptConnection when using Deferred SignalBehavior.

  • connection:Destroy() is unchanged as there is no equivalent to it in RBXScriptConnection.

  • Changed some comments and function documentation which may need to be rewritten and new ones may need to be added. Documentation for signal:Destroy() should be updated at the very least.

modules/signal/init.test.luau

  • Added 3 new tests

  • Added new function called DeferCondition to replace AwaitCondition where signal:FireDeferred(...) is used for better test accuracy in theory.

  • Tests were not ran in the other modules so it's possible behavior could be different, although unlikely.

… RBXScriptSignal behavior

+ Defer disconnecting connections in signal:Destroy(), so that any calls to signal:FireDeferred(...) during the same resumption cycle but before the :Destroy() call will fire to the connections.

This reflects native rbxScriptSignal:Fire() behavior and instance:Destroy() behavior with workspace.SignalBehavior set to Deferred.

Move signal:DisconnectAll() behavior to new function called disconnectSignalConnectionsStartingFromItem and removed references to _handlerListHead in the new function.
_handlerListHead is cleared and sent to the new function from signal:DisconnectAll() and signal:Destroy() instead.

Changed some comments which may need to be rewritten or new ones may need to be added.
@PolarisStarSystem
Copy link
Author

PolarisStarSystem commented Nov 9, 2025

I added some type improvements to Trove to this pull request. I would make a new pull request for this, but I do not see a simple way of doing that, so this will do.

Improvements are as follows:

  • Add missing Once function type to the Trove export type.

  • Only return ConnectionLike with Connect and Once in the Trove export type so the script editor properly lints the returned connection. This one I'm not 100% on because you'll get a type error if you pass the returned connection to a function that has a connection type argument with a metatable or is a RBXScriptConnection. Might be better to just deal with it add a unioned RBXScriptConnection to the return type instead.

  • Add [any]: any to Trackable types. This fixes the union type checking error when you do something like this:

local cleanup = Trove.new()
local signal = Signal.new()
cleanup:Connect(signal)
  • Add unioned RBXScriptConnection return type to Connect and Once in SignalLike and SignalLikeMetatable. This fixes the union type checking error when you type cast a TypedRemote and connect it like this:
local cleanup = Trove.new()
local event = TypedRemote.event("foo") :: TypedRemote.Event<>
cleanup:Connect(event.OnServerEvent, function() end)

The union type errors are issues I ran into related to the native Roblox type checker.

@PolarisStarSystem PolarisStarSystem changed the title Defer disconnecting connections in signal:Destroy() to reflect native RBXScriptSignal behavior Defer disconnecting connections in signal:Destroy() to reflect native RBXScriptSignal behavior + Trove type improvements Nov 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant