lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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.