Better way to make a retry pcall function?

Ive been trying to make a pcall retry function today and while I originally tried to do it with purely tuples (which failed) im not happy with my end result which involves a lot of table creation:

Here is my code:

local RetryPcall = {}

function RetryPcall.ActuallyTry(Function, Attempts, Arguments, ...)
	if ... then 
		local Args = {...}
		
		if Args[1] == true then 
			return select(2, ...)
		end
	elseif Attempts == 0 then
		return 
	else 
		Attempts -= 1
	end
	

	return RetryPcall.ActuallyTry( 
		Function,
		Attempts,
		Arguments,
		
		pcall(
			Function, 
			table.unpack(Arguments)
		)
	)
end

function RetryPcall.Try(Function, Attempts, ...)
	return RetryPcall.ActuallyTry(Function, Attempts, {...})
end

return RetryPcall

If anyone can think of a better way to do this please let me know, it may be obvious and im just not seeing it,

you can do

repeat 
--your code
until succes

Im not sure how that solves any of the problems I identified?

Use a loop as @Alaa4686 said.

function repeatCall(callback, attempts, ...)
    while attempts > 0 do
        local success, result = pcall(callback, ...)
        if success then
            return result
        end
        attempts = attempts - 1
    end
end

return function (callback, numAttempts, ...)
	return repeatCall(callback, numAttempts, ...)
end
2 Likes

Im not sure if either of you actually understand what the function is doing…

@HawDevelopment has given a function that retries a pcall until either it runs successfully or the code runs out of attempts in a smaller number of lines. You’ve just asked for a better way to do what the original code does, and as far as I can tell, the example given does it better.

You may not be aware, but pcall returns Success/Failure followed by at tuple of arguments. Their functions only return the first value of the tuple, not the entire tuple which as you can see from my original function is the intended behaviour.

You could detect if it failed on the script you’re calling this module from and just have it call the same function again when it fails

You can just make a few changes to get the intended behaviour

local Success, Data = pcall(function()
	return {Callback(table.unpack(Args))} --local Args = {...}
end)
		
if Success then
	return table.unpack(Data)
end

Well simply edit it. (Did this on mobile btw)

function repeatCall(callback, attempts, ...)
    while attempts > 0 do
        local results = {pcall(callback, ...)}
        if results[1] then -- No need for == true because it returns false if failed
            return select(2, table.unpack(results))
        end
        attempts = attempts - 1
    end
end

return function (callback, numAttempts, ...)
	return repeatCall(callback, numAttempts, ...)
end
3 Likes

The last return function is useless. It does nothing. You can simply replace it with

return repeatCall