[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: clumsiness of pcall() syntax and how we deal with it
- From: Konstantin Osipov <kostja@...>
- Date: Tue, 28 Apr 2015 13:19:04 +0300
Hello,
In a database, an exception is an important companion of
transactional semantics.
For example, if your data change command incurs a lock
conflict or a deadlock, the most natural way to deal with
it is to raise an error and abort the transaction.
This is why we extensively use Lua error() for errors such
as duplicate key, insufficient privileges, replication
conflict, etc.
In most cases people write code which is not handling
exceptions/errors at all and have their transactions
rolled back automatically on error:
begin()
select(...)
insert(...)
delete(...)
commit()
But there are rare cases when your business logic mandates
an action on error, and for these cases we offer people
Lua pcall():
begin()
select(...)
status, error = pcall(insert, ...)
if status then
look at the error, take action
end
delete(...)
commit()
The good thing is that this approach works and does what's
expected. But we encountered that pcall() syntax is not very
friendly to multiple return values and, generally,
towards a simple interpretation of the error. In other
words, the mechanics is there, but the syntax could, perhaps,
be improved.
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.
How to name the second argument? And what if a function returns
multiple arguments?
The solution we adopted is to never treat the second argument
as an error, but use a separate API to fetch the error.
We use a wrapper around pcall() which stores the error in a global
variable, when it occurs, and makes it available with last_error()
call.
This way we never have to look at the second return of pcall() as
an error:
status, tuple = pcall(insert, ...)
if status then
if lasterror.code == DUPLICATE_KEY then
...
else
error(lasterror)
end
end
As can be seen from the snippet, we also extended the error
handling logic to be able to raise and check additional
attributes of the error, such as code or error number,
and added an ability to re-throw an already raised error,
without change.
It would be nice to see support for these needs in some future
version of the Lua language. Especially since all the mechanics
is already there, and we're only talking about making it
easier to use.
--
http://tarantool.org - a NoSQL database in a Lua script