This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
Programming in Lua | ||
Part I. The Language Chapter 8. Compilation, Execution, and Errors |
Errare humanum est. Therefore, we must handle errors the best way we can. Because Lua is an extension language, frequently embedded in an application, it cannot simply crash or exit when an error happens. Instead, whenever an error occurs, Lua ends the current chunk and returns to the application.
Any unexpected condition that Lua encounters raises an error.
Errors occur when you (that is, your program) try to add
values that are not numbers,
to call values that are not functions,
to index values that are not tables, and so on.
(You can modify this behavior using metatables,
as we will see later.)
You can also explicitly raise an error calling
the error
function;
its argument is the error message.
Usually, that function is the appropriate
way to handle errors in your code:
print "enter a number:" n = io.read("*number") if not n then error("invalid input") endSuch combination of
if not ... then error end
is so common that Lua has a built-in function just for that job,
called assert
:
print "enter a number:" n = assert(io.read("*number"), "invalid input")The
assert
function checks whether its first argument is not false
and simply returns that argument;
if the argument is false (that is, false or nil),
assert
raises an error.
Its second argument, the message, is optional,
so that if you do not want to say anything in the error message,
you do not have to.
Beware, however, that assert
is a regular function.
As such, Lua always evaluates its arguments before calling the function.
Therefore, if you have something like
n = io.read() assert(tonumber(n), "invalid input: " .. n .. " is not a number")Lua will always do the concatenation, even when
n
is a number.
It may be wiser to use an explicit test in such cases.
When a function finds an unexpected situation
(an exception), it can assume two basic behaviors:
It can return an error code (typically nil)
or it can raise an error, calling the error
function.
There are no fixed rules for choosing between those two options,
but we can provide a general guideline:
An exception that is easily avoided should raise an error;
otherwise, it should return an error code.
For instance, let us consider the sin
function.
How should it behave when called on a table?
Suppose it returns an error code.
If we need to check for errors, we would have to write something like
local res = math.sin(x) if not res then -- error ...However, we could as easily check this exception before calling the function:
if not tonumber(x) then -- error: x is not a number ...Usually, however, we check neither the argument nor the result of a call to
sin
;
if the argument is not a number,
it means probably something wrong in our program.
In such situations, to stop the computation and to issue
an error message is the simplest and
most practical way to handle the exception.
On the other hand, let us consider the io.open
function,
which opens a file.
How should it behave when called to read a file that does not exist?
In this case, there is no simple way to check for the exception
before calling the function.
In many systems,
the only way of knowing whether a file exists is to try to open it.
Therefore,
if io.open
cannot open a file because of an external reason
(such as "file does not exist"
or "permission denied"
),
it returns nil, plus a string with the error message.
In this way, you have a chance to handle the situation in
an appropriate way,
for instance by asking the user for another file name:
local file, msg repeat print "enter a file name:" local name = io.read() if not name then return end -- no input file, msg = io.open(name, "r") if not file then print(msg) end until fileIf you do not want to handle such situations, but still want to play safe, you simply use
assert
to guard the operation:
file = assert(io.open(name, "r"))This is a typical Lua idiom: If
io.open
fails, assert
will raise an error.
file = assert(io.open("no-file", "r")) --> stdin:1: no-file: No such file or directoryNotice how the error message, which is the second result from
io.open
,
goes as the second argument to assert
.
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |