lua-users home
lua-l archive

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


On Tuesday, April 28, 2015, Thijs Schreijer <thijs@thijsschreijer.nl> wrote:
>
>
>
> > -----Original Message-----
> > From: lua-l-bounces@lists.lua.org [mailto:lua-l-bounces@lists.lua.org] On
> > Behalf Of Daniel Silverstone
> > Sent: dinsdag 28 april 2015 12:33
> > To: lua-l@lists.lua.org
> > Subject: Re: clumsiness of pcall() syntax and how we deal with it
> >
> > On Tue, Apr 28, 2015 at 13:19:04 +0300, Konstantin Osipov wrote:
> > > The first problem is in ambiguity of the second argument.
> > > In case there is no error, it's the return value of the function.
> > > Otherwise, it's a string with a message.
> >
> > I tend to use 'ok, result = pcall(xyz, blah)' and then:
> >
> > if ok then
> >   ...use result as useful result...
> > else
> >   ...result is the error...
> > end
> >
> > > How to name the second argument? And what if a function returns
> > > multiple arguments?
> >
> > Multiple returns is a toughie and I will admit I tend not to use
> > them in cases where I want to return errors too.  Then again I tend
> > to code functions which return an ok, result tuple most of the time
> > and then deal with wrappering them in assert() when I'd rather they
> > threw an error.
> >
>
> After recently having worked on http clients (with copas/luasocket/luasec) I have started to appreciate the luasocket functions protect, try and newtry for error handling.
>
> Thijs
>
>


I'm processing media content in a graph and have the same need: a way
to roll back partial changes when an error is thrown in a node.

My model uses tables as objects and I've settled on wrapping xpcall like so:

    do local xpcall = assert(xpcall)
    function Resource:pcall(fun, ...)
        return xpcall(fun, self.error_handler, self, ...)
    end end

This is still a work in progress. I'm deciding whether or not I want
to have an 'on_error' function that wraps this one, so that a call
would look like this:

    local result, result2, etc = self:on_error(function()
        --clean up state here
    end)
       :pcall(self.method, arg1,arg2)

Right now, it works like pcall and I check the error after the
function call. If it fails, I clean up and error again, except my
error message is the error object that I got back from the prior
xpcall. I pre-pend the new stack info to the original error message
and the result is a pretty good idea of 'what happened'.

Also, I include the object's `name` field in the error message, which
has been surprisingly helpful when things are concurrent.

Through this process, I have learned:

1: I have much to learn about errors and how to handle them.
2: Good programs have good errors.
3: Post error cleanup is hard and it's probably a good idea to start
with the hardest part of that problem, first.
4: Lua's error handling facilities are actually pretty decent, as far
as my limited experience is able to discern. Whenever I have thought
that it was missing something, I realized that I could make it myself
or that I really didn't want it in the first place.
5: This topic can descend into a debate over opinions very quickly. I
like those, but others have a limited tolerance for them, most likely
because they've already debated the topic and settled it in their own
mind.


One final point @Konstantin: In Lua, meta-programming is normal. That
is, whatever it is that you want can be programmed into Lua and if it
cannot, then it's probably worth discussion. But if it can, I doubt
that it would get added. Too many people deal with errors in too many
different ways.

-Andrew