This is the kind of macro that libraries like anyhow
or eyre
should have. Oh, they do!
On the other hand, it feels like macros like bail!()
(and perhaps this ensure!()
) should have been in the stdlib the whole time.
It also seems that ensure!()
is very related to ?
, it's as if Rust's ?
were too restricted and that's why we need additional macros. We already know what's the most generalized syntax for this: Haskell's do notation, but, is there a way to extend the power of ?
without going all the way there?
This also seems very related to assertions, to the point where another name for this could be try_assert()!
(but ensure()!
is a better name). Note that it's still useful to have both: assertions are used for fundamental assumptions, where the program can't possibly recover, and ensure just means that if the assumption is violated it's an error the caller could either handle or bubble up.
However, the most ergonomic way to write assertions (IMO) is using a macro like contracts
. I wonder if such attribute macro would be an useful companion for ensure!()
. #[ensure]
is a bad name though (it doesn't distinguish between preconditions and postconditions, that is, calling ensure!()
at the beginning or at the end of the function)
Anyway, I like when the Error
type can be left implicit. In most error libraries this is done by type Result<T> = std::result::Result<T, mylibrary::Error>;
but there's at least one library where whatever Error
type in scope is chosen implicitly: fehler
.
In fehler
, #[throws]
means #[throws(Error)]
and I think it is great. So perhaps ensure!(condition)
should mean ensure!(condition, Error)
for whatever Error
type that is in scope. The stdlib could provide a more structured way to say "this library has an error type that should be used implictly", but I think the fehler approach is good enough.
If there's a companion attribute macro, it would be nice if Error
could be left implicit there, too.