21 Mar 2015
Last week I pushed some changes that
switch capnproto-rust
over to using return-value-based error handling.
In particular, we no longer use the
default value fallback strategy discussed in
this previous post.
Now any method that might fail on malformed
input returns a ::std::result::Result<T, ::capnp::Error>
instead of a bare T
.
These changes remove a lot of complexity and
have allowed me to delete a significant amount of code.
They also provide, I think, a more honest interface for
users of the library.
Now the type signatures of the getter methods
make it clear exactly where input validation errors
are possible.
The try!()
macro makes it easy enough to deal
with such errors in a principled manner.
Here is what a small example looks like after the changes:
Notice that there are in fact two types of errors being dealt with here.
There is ::capnp::Error
, which gets returned
when a malformed pointer field is encountered in the encoded message.
There is also ::capnp::NotInSchema
, which indicates that
an enumerant or union discriminant value was
outside of the range defined in the schema.
The second type of error can occur if
the encoded data was constructed using a newer version of the schema.
Instead of ignoring such cases, as in the above code, we might instead
wish to propagate their errors.
Because ::capnp::Error
implements ::std::error::FromError<::capnp::NotInSchema>
,
we can easily accomplish that using the try!()
macro:
A year ago when I wrote the previous post on error handling,
the main reason that I decided not to go with return-value-based
error handling was that I thought it felt too heavyweight.
My sense now is that the try!()
macro and FromError
trait
can make things quite usable.