A little bit of context for xpcalls. (Question.)

I’ve been hearing about xpcall for a while, but didn’t fully understand it. My context of view is; A lua global which receives 2 main arguments, a function ran in protected mode, and a other function which will be executed if the one being ran in protected mode gave a error. My questions are, firstly, is this the correct point, or at least similar? Secondly, if the first function gives a error, and then the second one gets executed, will the error handler function (Second function) receive a ‘argument’, which would be the error, in string? Thirdly, what does the DevHub mean with:

It’s (Error Handler function) first result is the status code (a boolean), which is true if the call succeeds without errors.

The point is, what does it mean with ‘first result’?

If you wanna somehow describe those a little better, please leave a tiny bit of code, as a example. (Not required, and nor do I want spoonfeeding. )

The first item returned.
local FirstResult, SecondResult, ThirdResult, Etc = SomeFunction()

In the case of pcall, the first result is a boolean. If the first result is false, it means that it had an error and that the second result is a string containing the error message. If the first result is true, then it succeeded and the second result, third result, etc are the returns from the function you called in pcall.

3 Likes

I’m attempting the following code. What I’d expect, is that it would:

  1. Run the first function.
  2. Notice it has a error! Moving on to the second function.
  3. Second function is ran, output says 'ay'
  4. Prints that it didn’t have success, and prints the error, and ‘thirdresult’, which I’d expect to be nil, and, yes, it is.

But what I get on the output is:
nil

Success: true , Error: nil , #Result: nil

local succ, err, thirdresult = xpcall(
	function(e)
		print(bruhmomento)
	end,
	function(e)
		print(e)
	end,
	'ay'
)

print('Success: ', succ,', ', 'Error: ', err, ', ', '#Result: ', thirdresult)

And I’m starting to notice that xpcall might just be a whole different thing of what I expect.

From the API reference:

bool , Variant xpcall ( function f, function err, tuple args )

This function is similar to pcall, except that you can set a new error handler.

xpcall calls function f in protected mode, using err as the error handler, and passes a list of arguments. Any error inside f is not propagated; instead, xpcall catches the error, calls the err function with the original error object, and returns a status code. Its first result is the status code (a boolean), which is true if the call succeeds without errors. In this case, xpcall also returns all results from the call, after this first result. In case of any error, xpcall returns false plus the result from err.

I’ve already checked that, as you can see. Although, I didn’t understand much from there, that’s why I went here, to ask for ‘better’ explanation.

From my last reply, what I mean is, firstly, I’d expect it for the print statement to be ignored, since It was given a value which was nil, and that would give out a error. Then what I expected to happen, is that the ‘err’ / second function would be ran, and would print ‘ay’. But, that’s not what happened. And so, I’ve asked, once again, about further explanation.

xpcall is basically a try…catch, meaning it will run the first function with supplied arguments, and then call the second function if it errors. This will look something like this:

xpcall(function(...)
-- function that gets called
end, function(err)
-- function that gets called if the first function throws an error
end, ...)
3 Likes

Could you show a piece of code which, intentionally, gives a error at the first function, and then in the err handler function, it prints the error which was given?

Here is a sample script:

local function function1(...)
	print("function1 called with args:", ...)
	return "hi"
end

local function function2(...)
	print("function2 called with args:", ...)
	error("This is an error message.")
end

local errorHandler = function(err)
	warn("This is the error handler function.")
	warn("Error message:", err)
	return "nope"
end

local success, result = xpcall(function1, errorHandler, "a", "b", "c")
print("Successful? :", success)
print("Result:", result)

print("--------")

success, result = xpcall(function2, errorHandler, "a", "b", "c")
print("Successful? :", success)
print("Result:", result)

The output from this is:

function1 called with args: a b c
Successful? : true
Result: hi
--------
function2 called with args: a b c
(in warning text) This is the error handler function.
(in warning text) Error message: Workspace.Script:7: This is an error message.
Successful? : false
Result: nope

Since function1 didn’t error, the results are the same as if you used regular pcall.

When function2 errored, the message was passed into the errorHandler function, and the return value from that error handler is what xpcall returned.

2 Likes

I’ve just tested the sample, and It gave a, at least, for me, a un/expected error: Script:7: Cannot use ‘…’ outside a vararg function

I was expecting all that output, but, nope.

Sorry, I edited my post and forgot to change function2 to this:

local function function2(...)
	print("function2 called with args:", ...)
	error("This is an error message.")
end