An essay of checked exceptions in Rust

Two years ago I started the cex project to support checked exceptions in Rust. After eating my own dog food, I'd like to share some thoughts - with little code and more like an essay.

Checked exceptions provide code-as-documentation

#[cex] pub fn foo() -> Result!( () throws Bar, Baz );

The function signature indicates that foo() may produce Bar error and Baz error. Without checked exceptions, this information can only be found in foo()'s API document, or by checking foo()'s implementation. Bar and Baz should not be considered as "internal details" if they appeared in API document.

Checked exceptions are similar to "a big enum as the crate error type"

The big enum way may be regarded as "a summarizing error type per crate".

  • The same: both provide concrete error types.

  • The difference: checked exceptions provide precise error types for each function, while Result<T, TheBigEnum> can be aliased as Result<T> with pub type Result<T, E=TheBigEnum> = Result<T,E>;.

General vs specific

Various errors may occur during execution of a function.

  • If regarded as errors in different stages of the function's computation, they shoud be organized as variants of a whole enum which is the function's Error type. We may call it error-type-per-function strategy. These error types are most specific.

  • If regarded as independent errors which are general enough to deal with and specific enough to report, they can be organized as checked exceptions. Logging could be enabled to specify the location where error occurred.

cex vs anyhow

  • The same: both provide convenient mechanisms for propagating errors and attaching context.

  • The difference: cex requires extra annotations of error types, but does not require trait bounds std::error::Error, Send and Sync.

Checked exceptions are not necessarily infectious

Library users can choose whether or not to use checked exceptions even library author has utilized checked exceptions in library API.

  • Library author could provide "a big enum as the crate error", not for library API, but for library users' functions, the errors of which are all from the library API.

  • Library author could impl std::error::Error for each error thus impl std::error::Error for each checked exceptions. Library users can use Box<dyn std::error::Error> as the error type of their own functions.


Two chapters have been added to enumx book for demonstrating:

cex to crate error

cex as dyn std error

1 Like