lua-users home
lua-l archive

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


I think we agree, broadly, on the use of errors :) Use them where they are appropriate for the control flow of your program, prefer returns likewise in places where they make more sense (like when the caller may not want control flow interrupted, perhaps it is reasonable to ignore it or do something sequentially afterwards even on an unsuccessful return).

Regarding the use of “nil, errstring” only being a convention and not something unambiguous in the language, I think that’s the price we pay for using such a flexible language. It aims to be as non-prescriptive as possible, which makes it highly adaptable to all sorts of different uses.

That same flexibility does however work against it in the desktop scenario, when using third party libraries that may play a little fast and loose with those conventions. For example modules were a bit of a mess in 5.1 because every other library seemed to have a different idea about how the module convention ought to work. To come back to the error example, it may be that library writers err on the side of caution and use returns in their APIs where errors might be more appropriate, simply to avoid imposing prescriptiveness on the users of the API and therefore be maximally flexible, and this leads to situations where it looks like everyone’s writing code in a sub-optimal style. I don’t know, I’m just speculating there.

I don’t see there’s a lot we can do about that without turning Lua into something that it’s not :) Building things on top of Lua and imposing conventions etc on that, well that’s fine and exactly what Lua is great at. But it’s hard to bake any specific style into the language itself, simply because the variety of things it’s used for is so vast and core Lua consequently has to be very generic in some ways.

To take another example of how varied Lua-world is, I’m currently using Lua in a project on hardware with 84 kilobytes of available RAM. This was shortly after using it on another bit of hardware with 256 megabytes of RAM. I also use some of the same code on a PC with 16 gigabytes of RAM. Not every approach works perfectly across all those environments :-P
 
Cheers,

Tom

On 15 Jan, 2015,at 12:25 AM, Andrew Starks <andrew.starks@trms.com> wrote:

On Wed, Jan 14, 2015 at 5:40 PM, Tom Sutcliffe <tomsci@me.com> wrote:

Yes, me too. I've always been happy with how Lua handles nil and errors. You
can always wrap your call in an assert() to convert a nil result to an
error, if that fits your code flow/style better, but it's much less
convenient to convert an error to a nil. (Python's insistence in trying to
make everything use errors just plain aggrevates me). My background is from

How is `assert` harder and `pcall` easier? Perhaps there are many
times when you want to *silently* ignore a `nil, error_msg` return
value? If so, that would make sense. If not, then you must handle the
`nil, err` any way, correct?

When you are handling this sort of return value, I assume that you
typically handle it at the point of the return, as Javier states. If
this is so, is there a "most common" way that you find yourself
handling it? For me, that was typically something like:

```
if retval == nil then return nil, second_value end
```

Which, in turn, meant that the caller needed to handle it, right on
back to some main message handler, which would turn this into a reply.
And so, I can use assert, but assert is not quite the same. When I'm
debugging, I appreciate having the stack trace start at the point of
the error, not at the point that the function returned. Using `assert`
means that I need to change the code in some way, in order to retrieve
that.

environments where setjmp/longjmp were considered expensive operations so I
may be a little biased there, I suppose.

I assume (haven't needed to test) that an error is much slower than a
`nil, string` return, but there aren't many cases where I expect to
fail enough for that to matter, and in that case, `nil, string` makes
more sense.

I hope that people generally agree that ingrained behavior /
preferences that come from different languages are not reasons alone
to prefer one way over another. There should be good reasons to do one
way over the other. I'm reading these responses and I'm looking for
those good reasons and beyond preference (which is a fine enough
reason), I'm not understanding one.


As for making errors a proper type,
again I like the fact that Lua doesn't prescribe a particular type, and that
if you want to you can call error() with pretty much anything. It means you
have great flexibility in how you use errors, and having the standard
libraries not use them at all means they will not conflict with whatever
system you pick.
(Fun fact: error(nil) doesn't print an error message if you run it in the
interpreter even though xpcall(error, debug.traceback, nil) does return nil
plus a stacktrace in the second result so you'd expect it should print
something.
Sllightly more understandable fun fact: calling error with a non-string
means you won't get stack traces out of the standard xpcall(fn,
debug.traceback, ...) pattern and you have to roll something a little more
sophisticated.)

And this is what I do. Because I'm using `error` I can set a global
`_DEBUG` flag, which adds the stack trace to the message. I've also
included an error number, which then looks up the error text in a
table, making it easier to parse the errors that do need to handle. No
need for an error type and adding `__tostring` to the message makes it
print as normal error.

Lua's slight wrinkle with nil and false both being "falsey" makes far more
sense than the equivalent rules in say _javascript_ or Python (I do
occasionally trip myself up with zero being truthy in Lua but falsey in C,
but on balance I wouldn't want it to be falsey in Lua, it would be too
messy. I'm just too used to C sometimes.). Even the distinction of none vs
nil in the C API never bothered me, since it so rarely matters anyway.
Returning non-nil values following a nil never seemed illogical to me - I
don't find the arguments against such a construct to be that compelling. The
only thing I think is a bit messy is integer-indexed tables with nil
'holes'. Careful wording around 'well-formedness' in the table documentation
gets you so far, but I never did figure how for instance that was supposed
to work with the __ipairs metamethod. Ah: I see that is deprecated in 5.3 -
that simplifies matters! So I don't think I have any real compliants there
either.
In short, please don't change anything in this area, I like it fine just how
it is :-)
Cheers,
Tom

I agree with this. No need to change anything.

I was thinking more along the lines of how Lua libraries handle "soft"
errors and with conventions around errors, generally. `nil, string` is
an idiom that happily emerges from the language, without anything
within the language that gives it permission to exist as an "error
condition". Someone can just as easily design an API where this was
not error and in a few cases, this would even make sense.

It's that ambiguity that sours me on it. I think it's a potentially
hairy thing for an api developer to be deciding between

assert: "the program is not correct"
error: "you gave me something bad or something unexpected happened and
I'm quitting"
nil, string: "something that's normal happened that prevented me from
carrying out your request"

In production code, I would ignore the first, deal with the second and
then deal with the third, too. I can't see that being easier.

Since switching to errors, in my 30-ish file project I call `pcall` 5
times. Banishing nil, error_msg didn't have much impact on that number
because there are not that many times that actually I do anything
fancy with an error.

Hopefully there is a little more to this than just opinion and style
and that's why I think that this is a conversation worth having. As I
mentioned, I'm happy to keep doing what I'm doing while everyone else
picks the "Lua Way".

-Andrew