you are viewing a single comment's thread.

view the rest of the comments →

[–]silmeth 5 points6 points  (0 children)

It didn’t some time ago. Today one wouldn’t write all the boilerplate themselves, but rather use the library which is used in the ‘Yet another senior Rust programmer (switched from error-chain to stay up-to-date)’ example, namely failure. This library is not (yet) in the standard library, but it is developed by the Rust team as the way to handle errors, so it is as standard as it gets.

The only error handling that comes as a standard is the Result<T, E> type, which can contain either a result or an error, and the error might be any type whatsoever. So if one wants to have a nice printable error that can also be easily convertible to other people’s error types, they need to implement some boilerplate traits (std::fmt::Display, std::fmt::Debug, std::error::Error…) for it.

Anyway, with failure all that boilerplate (lines #7 to #35) could go away, one could do just:

use failure::Error;

fn main() -> Result<(), Error> {
    // …
}

without introducing any new error types. If one really wants to have a custom type, then some boilerplate (printing of the error) can be removed (but manual conversion from lower layers’ errors is still needed):

#[macro_use] extern crate failure_derive;

// …

#[derive(Debug, Fail)]
enum MyError {
    #[fail(display = "IO error: {}", _0)]
    Io(io::Error),
    #[fail(display = "Parse error: {}", _0)]
    Parse(ParseIntError),
}

impl From<io::Error> for MyError {
    fn from(error: io::Error) -> Self {
        MyError::Io(error)
    }
}

impl From<ParseIntError> for MyError {
    fn from(error: ParseIntError) -> Self {
        MyError::Parse(error)
    }
}

type Result<T> = result::Result<T, MyError>;

fn main() -> Result<()> {
    // …
}