[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Dealing With Errors in Lua
- From: Sean Conner <sean@...>
- Date: Fri, 27 Sep 2013 21:51:23 -0400
It was thus said that the Great Rena once stated:
> Recently I've been pondering how errors should be handled in Lua.
I've been trying to handle errors (in any langauge) for the better part of
twenty-odd years, and I'm still trying to come up with a method I like.
> I feel like it'd be more efficient if they returned an error code instead,
> or perhaps both - an error code *and* a string giving a human-readable
> error message. Though it feels awkward to return the human-readable message
> first, but the other way around breaks the "standard" that Lua libraries
> use.
> In fact I notice that io.open in particular *does* appear to be returning
> some type of error code, though the manual doesn't mention this. (At least
> not in the description of io.open, but maybe somewhere?)
Actually:
Lua 5.1, section 5.7:
Unless otherwise stated, all I/O functions return nil on failure
(plus an error message as a second result and a system-dependent
error code as a third result) and some value different from nil on
success.
Lua 5.2, section 6.8:
Unless otherwise stated, all I/O functions return nil on failure
(plus an error message as a second result and a system-dependent
error code as a third result) and some value different from nil on
success.
The value comes from errno, which is part of ANSI C. The actual text
comes from the Standard C function strerror().
> Of course once you're returning error codes, you need to assign names to
> them, because "2" and "13" aren't very descriptive, and it's important to
> be consistent. (i.e. if "2" means "No such file or directory" from io.open,
> it should mean that everywhere.) At least on POSIX-compliant systems, we
> have errno.h that defines a number of helpful error codes. These aren't
> 100% ideal though, because:
> 1) They mostly describe errors that can occur in OS calls. There aren't
> really useful error codes for things like "table expected, got number" or
> "malformed pattern".
> 2) The ISO C standard only requires EDOM, EILSEQ, and ERANGE to be defined.
> Beyond that, it's all system-dependent. In particular, Windows and embedded
> systems might not have errno.h at all.
False, if Windows claims to support ANSI C---errno.h is *part* of a
standard implementation of C. Now, Windows might not support much beyond
EDOM and ERANGE (I see nothing about EILSEQ in the ANSI C standard) but it
is there. And strerror() should return a human readable string given an
error message.
> 3) As far as I know, these names aren't exposed to Lua scripts anywhere in
> the standard libraries.
Well, aside from EDOM and ERANGE, what else to include? My own errno
module [1] uses a ton of #ifdef's (and yes, it's heavily Unix influenced,
but then again, I primarily use Unix). And even though I define a large
number of errors, I tend to only use a few:
EINTR - a system call was interrupted
ETIMEDOUT - an operation timed out
and sometimes EINVAL (invalid paramter to a system call). And that's
about it. Most of the time, as long as I can get a human readable version,
I'm happy.
> 4) People can't seem to make up their mind as to whether to return EFOO or
> -EFOO.
>
> Also, returning nil and error information doesn't fit so well with
> functions that can return nil in a non-error condition, e.g. string.find.
> That makes me feel more like any error should be handled with error(), but
> that's not terribly efficient either, and wrapping things in pcall() can be
> ugly. (try/catch sure would be nice to have!)
I tend to return an error indication (integer) as the last return code in
(C based) functions I write, even in the successful case, for instance [2]
static int fsys_chdir(lua_State *L)
{
errno = 0;
chdir(luaL_checkstring(L,1));
lua_pushboolean(L,errno == 0);
lua_pushinteger(L,errno);
return 2;
}
Most cases, I don't care about the actual error, and so for those I can:
if not fsys.chdir("/tmp") then
print("Bummer, dude!")
os.exit(1)
end
or, if I'm writing "real" code, I'll do it:
local okay,err = fsys.chdir("/tmp")
if not okay then
print("/tmp",errno[err])
os.exit(1)
end
It works for me.
> I've often also felt like Lua could stand to have a standard "warning"
> function. By default warning() might be something like:
> function warning(msg, ...) io.stderr:write(msg:format(...) .. '\n') end
> but the application could redefine it to send the messages elsewhere or do
> nothing.
You can do that now with error().
> I wonder what the Lua community thinks of this? I feel like a lot of these
> points could be addressed by just having an "error" library, that provides
> some useful error codes, an error/exception function that returns a table,
> maybe some type of try(function_to_try, function_to_handle_errors), and
> other such utilities. But then it's necessary to decide on a standard list
> of error codes (especially you don't want to have to edit the list later
> and have some programs using EFOO and some using EBAR for the same case
> because EBAR didn't exist when they were written), and it would be
> troublesome if some of the libraries your program uses are using this and
> some aren't. But maybe it could be done?
Years ago when I was in college, I was writing a program [3] and the issue
of error handling came up. I couldn't log the error to the screen because
the system would be mostly unattended and even if it wasn't, the message
might scroll off (or the screen cleared) before a human operator could check
it. So let's log it to a file. But what happens when the drive fills up?
Okay, in that case, check to see if a printer [4] is hooked up and online and
print to that. But what if that's offline, or there is no printer? I was
stuck.
So I asked one of my college instructors what to do. His reply, as
distateful as it seems, can't really be argued with: If you don't know how
to handle the error, then don't check for the error.
Also, over the past twenty-odd years, I've tried plenty of methods to
handle errors. I *always* end up abandoning the code for some reason (it's
hard to use, too verbose, doesn't match).
-spc (and I'm not a real fan of exceptions)
[1] https://github.com/spc476/lua-conmanorg/blob/master/src/errno.c
[2] https://github.com/spc476/lua-conmanorg/blob/master/src/fsys.c
[3] A BBS door.
[4] This was back in the days of form-feed paper and dot-matrix
printers.