What problems are there in a yielding debounce? I’ve heard many people say that a time-comparison debounce is much better than a yielding debounce since “yielding is bad”. But what makes it bad in this situation?
From my limited understanding, whenever an event is fired, a new lua thread is made. Yielding in this thread wouldn’t seriously affect other threads that are supposed to resume.
Yielding debounce
local debounce = false
event:Connect(function()
if debounce then return end
debounce = true
task.wait(3)
debounce = false
end)
Time-comparison debounce
local lastTime = os.clock()
event:Connect(function()
if os.clock() < lastTime then return end
lastTime = os.clock() + 3
end)
Of course the second method looks a lot cleaner. However, my question is regarding the issues in a yielding debounce and what problems they cause.
If yielding isn’t inherently bad, would it not be better to disconnect the connection until the cooldown passes? Something like this:
Disconnecting debounce
local conn
local function onEvent()
conn:Disconnect()
task.wait(3)
conn = event:Connect(onEvent)
end
conn = event:Connect(onEvent)
A yielding debounce in one-way communication between two scripts won’t yield the script that fired the event. If you use a remote function/bindable function, then that’s where using a yielding debounce isn’t the best idea, unless the pause is intentional.
Yielding gets you into trouble in larger systems. In a small, isolated event trigger like this, it probably doesn’t matter. Some people might disagree with me there, but it’s just not that bad in small contexts like this. I would never yield on main thread though.
I wouldn’t disconnect/reconnect though, because you are crossing paths with logic to both handle the event and hook up the event, which is a bit messy. And if you ever wanted to pass that connection elsewhere to be disconnected by something else, you’d break that since you’re creating a new connection there.
All that being said, I use time comparisons for most debounces. That’s because I can go a little overboard to avoid any explicit yielding. I find it to be a bit cleaner personally.
Time-comparison is definitely cleaner when working with multiple instances of a debounce (such as player-specific cooldowns), since you will need to organize each instance within a table to keep track of everything. Storing the time is usually pretty convenient.
I think, overall, time-comparison simply offers more information about the state of your function (that is, it actually tracks time instead of just running state), and that additional information may provide unforeseen utility in the future, which I think tips the scale.
That all being said, I’m terrible at following this advice and struggle to break the habit of yielding debounces.
Ah ok. If possible, please can you explain the problems yielding causes in larger systems?
I didn’t quite understand this. Are you referring to maids/janitors? If so, I’ve never used those so I’m not sure about how they work but I’m guessing they handle your connections in a different thread?
And yeah, I do use time-comparison debounces all the time but I was just confused about why so many people treat yielding debounces as a taboo. I think the main question boils down to “what are the issues related to yielding?”
I do agree with @MysteriousVagabond on the point he made about using a time-comparison debounce when working with multiple instances as you would only want one connection handling all of those instances instead of one connection per instance.