How to use pcall properly


  • Pcall is a function which catches an error and returns it . For example, if you had a function like

    local function add(x, y)
    

	if math.random(1, 2) == 1 then
    		error("adding failed")
    	end
    	return x + y
    end
    

    then you'd use a pcall. An actual use for this would be for things like datastores and http requests, since most, if not everything internet-based has a chance to fail. However, if we took the function above and someone wanted to pcall it, most people would just go and do something like this.

    local success, value
    while not success do
    	success,  value = pcall(function()
    		return add(1, 1)
    	end)
    end
    print(value)
    

    or just pcall it once like

    pcall(function()
    	print(add(1, 1))
    end)
    

    However, you create a new function to call these other functions! Every function in Lua, built in or not, can be called the same way and there's no special way you need to call it like only using the above. To solve this problem, you can just do

    pcall(add, 1, 1)
    

    so that you don't need to create a whole new function. In case you didn't know, you can specify the parameters to pass into the function after you specify the function.

    Now, you might be asking how to apply this to a Roblox function. You can't just do

    pcall(game:GetService("HttpService"):GetAsync, "example.com")
    

    In order to solve this, you'll need to understand that

    function foo:bar(x)
    	print(self, x)
    end
    

    is the same as

    function foo.bar(self, x)
    	print(self, x)
    end
    

    and that

    foo:bar(x)
    

    is the same as

    foo.bar(foo, x)
    

    With this knowledge, we can just do

    pcall(game:GetService("HttpService").GetAsync, game:GetService("HttpService"), "example.com")
    

    Since people usually use pcalls for datastores, I'll use that for the next part.
    What if the pcall fails, though? The pcall would be useless. To fix this, you need to just retry the request. However, assuming it's an error from you exceeding the call limitations, you'll need to wait in between like

    local datastore = game:GetService("DataStoreService"):GetGlobalDataStore()
    local success = pcall(datastore.SetAsync, datastore, "foo")
    while not success do
    	wait(10) --You should not use this unless the thing you are checking for does not have an event when it changes.
    	if game:GetService("DataStoreService"):GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementAsync) > 0 then
    		success = pcall(datastore.SetAsync, datastore, "foo")
    	end
    end
    

    Now your pcalled code won't have a random chance of breaking everything else.


  • @hiimgoodpack
    Another good example of where a function will error's the GetNameFromUserIdAsync and GetUserIdFromNameAsync functions, as they'll error if the user/userid doesn't exist.

Log in to reply
 

Looks like your connection to Scripting Helpers was lost, please wait while we try to reconnect.