Lua has two categories of errors that can be communicated across function calls.
The first category includes exception-like errors. The second includes errors given by return values.
Now, the documentation avoids words like "exception," "throw," and "catch." But I'm going to use the exception language because I think it clearly communicates the behavior that's going on here.
First I'll show you an example of an error thrown by the standard library which is then caught by the interpreter and printed.
> io.write(false)
stdin:1: bad argument #1 to 'write' (string expected, got boolean)
stack traceback:
<other stuff here>
In this case, there's a bad argument to the io.write
function.
If you want to throw a custom exception error, then you
can call the built-in error
function with a string
describing the error.
> function f() error('my error msg') end
In this case, my function f
will throw that error;
the interpreter will catch it and print my error msg
.
> f()
stdin:1: my error msg
stack traceback:
<other stuff here>
The built-in assert
function accepts as input a boolean
and an error message.
It throws the error message if the boolean is false, like this:
> cond = false
> = assert(cond, 'ruh-roh')
stdin:1: ruh-roh
stack traceback:
<other stuff here>
However, if the condition is true, then it simply returns the inputs it receives.
> cond = true
> return assert(cond, 'ruh-roh')
true ruh-roh
-- Editor's note: the "return" acts the same as an =.
A common pattern in Lua, for functions that return error messages, is to first return a boolean indicating success or failure, followed by, in the success case, the useful return values; or in the failure case, an error message.
assert
works well with this pattern.
I'll demonstrate by creating two functions that return
success or failure depending on which one I call.
> funciton bad() return false, 'was bad' end
> function good() return true, 42 end
And we'll see that
assert
easily wraps these function calls.
In this case it'll throw the error message:
> = assert(bad())
stdin:1: was bad
stack traceback:
<other stuff here>
And in this case - the good case - it will simply return the useful return values:
> = assert(good())
true 42
The built-in pcall
function makes protected function
calls.
It basically wraps a call to catch exceptions.
You use it by first sending in the function that you want to call followed by parameters that you want to give to it.
> =pcall(print, 'a good call')
a good call
true
It calls the function with the given parameters. The first return value is going to be a boolean indicating success or failure. The others are either going to be the called function's return values, or an error message if an exception was thrown.
I'll give an example of a case where an exception is thrown.
> = pcall(io.write, false)
false bad argument #1 to '?' (string expected, got boolean)
In summary, pcall
converts exception-like errors
into return-value errors.
I like to think of it as a sort of inverse of the
assert
function.
There's another built-in function called xpcall
which
offers basically the same functionality as pcall
, except
that one of its input parameters is a callback function
to handle exception-like errors.