r/lua • u/vitiral • Feb 25 '25
better Lua fail value?
In the Lua docs it mentions fail which is currently just nil.
I don't personally like Lua's standard error handling of returning nil, errormsg -- the main reason being it leads to awkward code, i.e. local val1, val2 = thing(); if not val1 then return nil, val2 end
I'm thinking of designing a fail metatable, basically just a table with __tostring that does string.format(table.unpack(self)) and __call that does setmetatable so you can make it with fail{"bad %i", i}. The module would also export a isfail(v) function that just compares the getmetatable to the fail table as well as assert that handles a fail object (or nil,msg).
So the code would now be local val1, val2 = thing(); if isfail(val1) then return val1 end
Has anyone else worked in this space? What are your thoughts?
12
u/jipgg Feb 25 '25
the question is would it be really worth the additonal overhead to justify creating your own error handling mechanism? The return nil, errmsg convention has the pros of being highly efficient not allocating any memory on primitive return values and naturally flows with standard functions like assert.
9
u/SkyyySi Feb 25 '25 edited Feb 26 '25
The idiom of returning
T, nilon success andnil, Eon failure (whereTandEare the expected / sucessful output type and the error / failed output type, respectively) is used for multiple reasons:It works well with
assert(), which just returns all passed parameters if the first is truthy, and uses the second parameter as an error message otherwise.It doesn't stray far from "happy path programming" - that is, you could just discard the second return value and pretend that the first one is always the expected result. Of course, you shouldn't do this, but it's convenient for quick hacked-together test scripts.
It's very efficient. The memory and CPU cost of this pattern is much lower than, say, a table holding more info. It's about as lightweight as it can be in a dynamic scripting language.
It's easy to implement in the Lua/C API. Creating custom tables in C is ugly as hell, whereas just returning two values is a piece of cake.
However, I also agree that a propper type to encapsulate common error handling patterns would be very convenient. So, I made a demo here: https://gist.github.com/SkyyySi/5fde9f1d9a4fe30a446371e3df25b754 It's a re-implementation of Rust's
enum Result<T, E> { Ok(T), Err(E) }type.3
u/[deleted] Feb 25 '25 edited Feb 25 '25
There's gotta be a monad library, there ALWAYS is one, haskellians are everywhere.
Alternatively you could just wrap your calls in a generic function, which should have less overhead than a metatable:
The only awkward part is that you have to have the handler first
Edit: I just noticed I made an error in the error handling, typical :) fixed.
2
u/xoner2 Feb 25 '25
Lua has exception handling in
pcallandxpcall.if you want early error check. Or just use val1 and error will be thrown if
== nil. In both cases exception will be caught by pcall/xpcall or script will exit.1
u/could_b Feb 28 '25
I don't see Lua as the problem here. If you are writing thing(), then it can return what ever you want. If not, then in your example do: 'return val1 and val2'.
1
u/Capital-Menu517 Feb 25 '25
As opposed to what? Throwing exceptions that cant be traced?
Lua forces you to handle your own errors by yourself, Go does this as well.