How can I call a function with an absolute guarantee another will be executed when it stops?

Here’s what needs to happen:

  1. (thread A) Create thread B, wait for BindableEvent “FinishedEvent”
  2. (thread B) Mystery function fires, which may or may not have an error
  3. (thread B) FinishedEvent fires when the mystery function either finishes or has an error
  4. (thread A) Finish waiting for FinishedEvent

The problem is getting past step 2.
pcall does not guarantee getting past step 2.
xpcall does guarantee getting past step 2, however the functions that would cause pcall to fail instead return the error “attempt to yield across metamethod/C-call boundary”.
Is there a way I can always get past step 2, while still having the function work as intended.

At the end of the function, you could have it call the next, and then repeat.

1 Like

Did you read the question at all?
Firstly, it’s a mystery function. I can make no guarantees about what the function does, like having it call the next function.
Secondly, the whole issue here is that the mystery function may have an error, thus whatever comes after it never executes.

Can you show some code of what you’ve tried to get a better grasp at what you’re trying to do? There may be a better solution for your problem and what you’re describing sounds a bit weird in general.

2 Likes

It’s for a script which acts as an alternative to game:BindToClose, since that function has an annoying bug in Studio that has been reported but is being ignored since bugfixing in Roblox has ground to a halt.

game:BindToClose(function()
	local remaining = #Bound
	
	if remaining > 0 then
		local FinishedEvent = Instance.new('BindableEvent')
	
		for _, Pair in pairs(Bound) do
			spawn(function()
				local status, err = pcall(Pair.func)
				remaining = remaining-1
				if remaining <= 0 then
					FinishedEvent:Fire()
				end
				if not status then
					error(err)
				end
			end)
		end
		
		FinishedEvent.Event:Wait()
	end
end)

A “Pair” in this script is a function bound to close, and the script that function came from (if that script is destroyed, the function is unbound).
The problem is, that if pcall(Pair.func) stops the function it was called inside, it doesn’t do remaining = remaining-1, which means remaining <= 0 is never true, which means FinishedEvent never fires, which means this whole function never finishes, which means Studio crashes.

I can make it so that pcall(Pair.func) doesn’t have an error, by fixing whatever error is inside Pair.func, but I’d rather guarantee that this function as a whole cannot possibly crash Studio without introducing weird behaviour like timeouts, or a loop that continuously checks the status of coroutines.
Actually, that loop sounds like a good idea now. It’d only add a one-frame delay to the game closing process now that I think about it.

Edit: That last idea doesn’t work, because if a coroutine dies while yielding (e.g. when using BindableFunction) it doesn’t change its status to dead.

What are you trying to resolve here? You can’t expect people to know what you’re talking about without providing context. Also, spreading rumours is a no-no. Bug reports aren’t ignored and the engineering team hasn’t stopped addressing such bugs either.

Sorry, got confused on how you worded your explanation and issue. If I understand your steps correctly, your script should be running. I do not know what you mean by “pcall does not guarantee getting past step 2”. As I see it, step 2 is merely an informative step rather than something that is happening. Is calling the mystery function the issue?

You’re not quite understanding the problem.
The code after the pcall does not run at all if the function in pcall has an error during a yield.
pcall is not a 100% safe call.
ypcall was meant to work in this usage case, but ypcall is no longer documented and functionally identical to pcall.

Oh didn’t know that one, can’t help with this

I see. If it is a roblox bug then I do not know how to fix that, but I have a few questions for you.
What is the bug in BindToClose that is more severe than pcall never returning? Does it really require you to implement a new BindToClose method entirely?
And can you not just make a quick solution, such as a timeout, to fix the issue?

You do realize you have 30 seconds for the bind event to wait?

The bug in BindToClose is that if it’s used in Studio, and a script that bound something is deleted, a popup error window appears. Which is a minor annoyance.
Your post made me think that maybe I should just stick with regular BindToClose for now, but…
It turns out that game:BindToClose has the same flaw as my own BindToClose function! It’ll crash Studio if it runs a function that has an error while yielding.
Apparently, the engine programmers at Roblox didn’t make a better system than me, they hit the same wall. Or they just never noticed the flaw.

Edit: It turns out that the crash is actually caused by running an unassigned BindableFunction. It affects both my own BindToClose system and the regular BindToClose system, but the regular BindToClose system has a timeout.

You should start reading the wiki, you’re not supposed to use it in studio.

game:BindToClose(function()
if game:GetService’RunService’:IsStudio() then
print’In-Studio’
return
end
–run code
end)

1 Like