Xpcall() or pcall()?

Hello,

So I am currently rewriting my DataStore ModuleScript, my older version was very Messy and had a lot of inconsistencies, and this may have some too, and now I am currently in part with Retrieving the Data from DataStoreService.

I am Aware when doing this, I must use a pcall() to put the code under a protected mode to prevent errors, and “appearently” you have better access to the Service, Looking at the Arguments of pcall(), There is only:

  • function()
    The function() to put under protection mode

And you could use it like this:

local Success, Err = pcall(function()
    Code()
end)

if Success then
    FireCode()
elseif not Success then
    FireError()
end

ypcall() is a Deprecated Global, Apparently It’s an older version of what is now pcall(), Assuming it does the exact same thing, It should be:

local Success, Err = ypcall(function()
    Code()
end)

if Success then
    FireCode()
elseif not Success then
    FireError()
end

But what about xpcall(), It has a Custom Error Handler?
Looking at its Arguments, It does:

  • function()
    The function() to put under protection mode

  • Error
    The function() for when an error Occurs

The way it could be used is:

local Success, Data = xpcall(function()
    return Code()
end, function()
    FireError()
end)

if Success then
    FireCode()
end

These are just a Couple of Uses for pcall(), ypcall(), and xpcall(),
But which would be better to use when Handling DataStores? These are Two Versions of my Code utilizing both pcall(), and xpcall() :


xpcall() version:

function Profile:Load(Plr: Player)
	local Success, Data = xpcall(function()
		return Profile.DataStore:GetAsync("Player_"..Plr.UserId)
	end, function()
		Plr:Kick("Failed to Access DataStores")
	end)
	
	if Success then
		if Data then
			Profile.Session[Plr.Name] = Data
		else
			Profile.Session[Plr.Name] = {
				["Level"] = 1;
				["EXP"] = 0;
				["Cash"] = 0;
				["Item"] = {};
				["Banned"] = false
			}
		end
	end
	Profile.Stats(Plr)
end

Standard pcall() version:

function Profile:Load(Plr: Player)
	local Success, Data = pcall(function()
		return Profile.DataStore:GetAsync("Player_"..Plr.UserId)
	end)
	
	if Success then
		if Data then
			Profile.Session[Plr.Name] = Data
		else
			Profile.Session[Plr.Name] = {
				["Level"] = 1;
				["EXP"] = 0;
				["Cash"] = 0;
				["Item"] = {};
				["Banned"] = false
			}
		end
    else
        Plr:Kick("Failed to Access DataStores")
	end
	Profile.Stats(Plr)
end

Both xpcall() and pcall() Appear to be Valid Options with this use, Which would be more beneficial with Handling DataStores?

Can you Help?

Thanks.

2 Likes

id use pcall you arent really using the error, you could just use pcall and check success instead of worrying about xpcall error handling

tldr: pcall is simpler.

2 Likes

xpcall() is just a Custom Error Handler, In this Case, if it fails, it will kick the Player if it fails

But xpcall() removes an Extra Step than pcall() with if statements

2 Likes

i dont see the improvement, you’re still typing if success then in both code, using xpcall has a whole extra error function() to kick the player instead of just typing else plr:kick() end

I personally would only use xpcall when actually needing the specific error

1 Like

well, i could remove the Success part, since if it fails, it will kick the Player, but that might have a bad effect with the code

1 Like

and you’d still be localizing local Success, Data?
if you’re gonna localize it, you may as well just use it, instead of an entire function

also removing if success then end and just setting the table or error string regardless is kinda wasted resources

1 Like

I can always do this:

local _, Data = xpcall(function()

The First Argument is always a Boolean, using _ would sort of remove its use

yes, but the error part with xpcall() will fire without saying if not Success then, then i have if Data then

1 Like

I know this has been marked as solved, but I’d still like to add my two cents.

I personally believe that it is mostly up to preference if you’re going to handle the error other than just using an early-exit (guard clause) pattern.

But for your specific use case, where all you do is kick the player, I don’t think you should use xpcall over pcall for a couple of reasons.

  1. You’d have to wrap the Kick regardless because you cannot otherwise pass the Player instance, thus resulting in an extra function call.
  2. It’s better off using early-exit pattern in this case.
local ok, result = pcall(...)
if not ok then
    player:Kick("Failed to acquire player save data.")
    return
end

-- Do your thing.
2 Likes

This is probably the only time I would use xpcall()

function Profile:Save(Plr: Player)
	local Success, Data = xpcall(function() --"data" might not be nessecary
		return Profile.DataStore:SetAsync("Player_"..Plr.UserId) -- forgor Second Argument
	end, function()
		warn("Failed to Save Data for", Plr.Name)
	end)
	
	Profile.Session[Plr.Name] = nil
end

Just use xpcall because pcall and xpcall are the same and xpcall has shorter code.

TLDR: xpcall is pcall but shorter

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.