lua-users home
lua-l archive

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


On Fri, 27 Sep 2013 11:50:01 -0400
Rena <hyperhacker@gmail.com> wrote:
> Recently I've been pondering how errors should be handled in Lua.

I brought up this issue 6 months ago, when lhf seemed to understand what I meant:

>>From: Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
>>To: Lua mailing list <lua-l@lists.lua.org>
>>Subject: Re: fine-grained lua_pcall() error processing
>>Date: Wed, 13 Mar 2013 00:20:14 -0300
>>Reply-To: Lua mailing list <lua-l@lists.lua.org>
>>User-Agent: Mutt/1.4.2.2i
>>
>>> Too bad Lua doesn't use its own error() model to throw an error object/table before flattening it to a string.  
>>
>>You can throw any Lua value with lua_error() or error(), but I guess
>>you mean that internally the Lua core could thrown something else.

... then again a couple of weeks ago but both lhf and Roberto shot it down (ouch:). I can't tell if it's a misunderstanding but I doubt the reference links I provided [1][2] were consulted. [1] is a Lua script scanning the Lua ANSI C source code to identify how many distinct errors the Lua VM may throw. [2] is a saved output from [1]; dumping where those errors are thrown from, each row mentions the LuaVM C filename and [begin; end] char indices.

It's probably not comprehensive but gives a fair idea of how coarse the handful integer Lua error codes are vs various errors the VM may actually throw.

Again I am only talking about errors generated by the Lua VM from C (i.e. NOT errors triggered from client/script). Most native Lua errors /do/ get sprintf()'ed to a string before reaching the error callback, at which point there's a logic drop-off because only a human being can make sense of them. Don't agree? Check the links :)

> (..)
> I find this method isn't terribly efficient. At least if the returned
> strings are constant, they get interned and so comparing strings is as fast
> and simple as comparing integers. But some functions add details into their
> errors, which then means they have to be parsed. E.g.:
> > =io.open('nope', 'r')
> nil    nope: No such file or directory    2
>
> To determine the actual error now requires some string parsing which is a
> bit inefficient. And there are edge cases:
> > =io.open('/home/rena/No such file or directory', 'r')
> nil    /home/rena/No such file or directory: Permission denied    13
> (so a simple err:find("No such file") would fail here)

I don't think it's possible to obtain a deterministic "reverse-map" from an error string to a fine-grained error code, since part of the error string may contain string chunks from the client script that triggered the error, at worst complete garbage which is what an error handler should... uhh... handle :) It's not even desirable because it's an anti-pattern and there's little resource constraint for an error handler; the constraint is "correctness".

> 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.

Either solution would be great.

IMHO the cleanest would be to declare fine-grained error enums, then delegate the error string flattening until later, so the Lua VM throws an error /object/ (table) with a __tostring metamethod to emulate the current behavior or something to that effect.

> 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.

I'm guessing Lua's POSIX abstraction model would work fine with finer error reporting. The error string would contain more information (possibly platform-dependent) than any error enum but for x-platform code a finer error code would be enough for most cases.

> (try/catch sure would be nice to have!)

It would if there were free, but they're not :)

> error() has the same "issue", too: the standard is to return strings, which
> then need to be parsed (especially if you don't want to display the whole
> stack trace from xpcall() in your UI). I feel like it'd be nice if we
> returned tables (exception objects, if you will), but then once again we
> need to agree on standards - what fields the table should have, and what
> exactly they should contain.

A unique error enum would get you pretty far. You /could/ inspect the error's varargs based on its fmt if you really must.

> Personally I'd expect them to contain at least
> the source file, source line, error message, and error code, and stack
> traceback if xpcall() were used, but maybe there are other useful things to
> add.

You can generate all those from the error callback, there's no need to front-load them.

> 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.

Many SDKs solve that problem by reserving a native enum range, with plenty left for client code, and/or return dynamically-generated IDs so multiple client libs don't clash.

cheers,

-- p

[1] http://www.laufenberg.ch/lua/err_scan.lua
[2] http://www.laufenberg.ch/lua/dump.log