Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic handler code that relies on a std::error::Error implementation #100

Closed
nicholasbishop opened this issue Jul 12, 2020 · 2 comments
Closed

Comments

@nicholasbishop
Copy link

I have some code that tries to be generic over the error type. It works fine with a "specific" error type, e.g. one derived with thiserror, but it doesn't work with anyhow because anyhow::Error does not implement std::error::Error. I saw a similar issue here: #25, but I think my use case is a bit different so I'm hoping you could provide some guidance about how best to proceed. This example is a bit long but hopefully communicates what I'm trying to do:

use std::error::Error as ErrorTrait;
use std::io::ErrorKind;

type Callback<E> = dyn Fn() -> Result<String, E>;
type ErrorHandler<E> = dyn Fn(E);

fn default_error_handler<E: ErrorTrait>(error: E) {
    println!("an error occurred: {}, source: {:?}", error, error.source());
}

fn io_error_handler(error: std::io::Error) {
    match error.kind() {
        ErrorKind::NotFound => println!("io error: not found"),
        _ => println!("some other kind of IO error"),
    }
}

struct Thing<'a, E: ErrorTrait> {
    callback: &'a Callback<E>,
    error_handler: &'a ErrorHandler<E>,
}

impl<'a, E: ErrorTrait> Thing<'a, E> {
    fn run(&self) {
        match (self.callback)() {
            Ok(val) => {
                println!("callback returned: {}", val);
            }
            Err(err) => {
                (self.error_handler)(err);
            }
        }
    }
}

fn callback1() -> Result<String, std::io::Error> {
    Ok("hello from callback1".into())
}

fn callback2() -> Result<String, anyhow::Error> {
    Ok("hello from callback2".into())
}

fn main() {
    let thing1 = Thing {
        callback: &callback1,
        error_handler: &io_error_handler,
    };
    thing1.run();

    let thing2 = Thing {
        callback: &callback2,
        error_handler: &default_error_handler,
    };
    thing2.run();
}

The basic idea is that I want to have a callback that can return any type of error. There is also a customizable error handling function to handle errors returned by the callback. The default error handler works for anything that implements std::error::Error, but can also be replaced by a more specific error handler that operates on a particular error type.

Of course, the code above does not compile because thing2 tries to use anyhow::Error as the error type, which does not implement std::error::Error. I'd be interested to hear any suggestion about how to make this API work better. Do I just need to have explicit support for anyhow::Error, separate from other error types? Or is there some more general way to make this work? Thanks :)

@dtolnay dtolnay changed the title Question about anyhow::Error not implementing std::error::Error Generic handler code that relies on a std::error::Error implementation Jul 12, 2020
@dtolnay
Copy link
Owner

dtolnay commented Jul 12, 2020

You could have a separate anyhow::Error handler fn, or if you need them to be a single handler fn then something like this would work:

- fn default_error_handler<E: ErrorTrait>(error: E) {
+ fn default_error_handler<E: Into<anyhow::Error>>(error: E) {
+     let error = error.into();
      println!("an error occurred: {}, source: {:?}", error, error.source());
  }

@nicholasbishop
Copy link
Author

Thanks for the suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants