Hacker News new | ask | show | jobs
by autarch 2605 days ago
Rust's type system + the failure crate (https://crates.io/crates/failure) is the nicest I've seen. It's similar to Haskell in that errors are part of the return value of a function, and the type system enforces handling of this.

_But_ Rust also includes some really nice syntax for passing errors through so I can write this:

    use failure::Error;

    fn foo() -> Result<String, Error> {
        may_return_an_error()?;
        might_return_a_different_error()?;

        if some_condition {
            return Err(MyPackageError { detail: "..." })?;
        }
        Ok("foo")
    }
The `failure::Error` type automagically wraps any error. That means I can go through many levels of my stack returning `failure::Error` and at any point in the call chain I can decide to examine the error type instead of writing `some_func()?;`, which would pass the error back.

The only part I don't like is that I need to add a `?` when I return my own errors. I don't totally understand this but from what I sort of understand the reason is that `?` invokes `.into()` on the returned object, which is what lets me return a (wrapping) `failure::Error` instead of a `MyPackageError`.

The upshot of all this is that "ignoring" errors is quite easy, as long as _somewhere_ in my call chain I actually do handle the error. The type system will enforce this for me, as attempting to treat a `Result<String, Error>` as just a String will cause a compile time error. I have to unwrap it and either ignore the error (which would lead to a runtime panic if there _was_ an error) or do the right thing, which is to explicitly handle both the ok and error cases.

I'm working on a CLI program using this system, and I can bubble all the errors up to the main entry point of the CLI. At that point I can turn errors into a print to stderr and an appropriate exit code.

1 comments

This sounds exactly like Java's checked exceptions.
The two are closely related concepts. You can model checked exceptions as a secondary return type, except without the same first-order representation (e.g. inability to specify checked exceptions in generic terms).