Handling callback errors idiomatically

Hi,

In several of my libraries, I have functions taking callbacks as arguments and, depending on the application, these callbacks may generate errors or not. In such a situation, Is the idiomatic solution to have two functions, say

pub fn exe(f: impl Fn(f64) -> f64) -> Result<f64, Error<!>>;
mod err {
    pub fn exe<E>(f: impl Fn(f64) -> Result<f64, E>) -> Result<f64, Error<E>>;
}

where Error is an error struct with a slot taking a generic E to propagate errors? To name the two functions exe, I introduced a sub-module err; is this the expected presentation?

1 Like

you may want to have a look at thiserror or anyhow.

To name the two functions exe, I introduced a sub-module err; is this the expected presentation?
I, personally, found it a bit confusing, I'd just do:

pub fn exe0(f: impl Fn(f64) -> f64) -> Result<f64, Error<!>>;
pub fn exe1<E>(f: impl Fn(f64) -> Result<f64, E>) -> Result<f64, Error<E>>;

Plus, I don't think you should be using the never type like that

Why not? May you elaborate? With #![feature(exhaustive_patterns)] (hopefully enabled by default in the future), the struct case that holds the error E may simply be ignored in pattern matching. A single error type for both cases but with refutation of some patterns when fit seems ideal to me.

This is usually done with a trait with an associated type:

trait DoTheThingTheCallbackIsFor {
    type Error;
    fn the_thing() -> Result<Thing, Self::Error>;
}

and for convenience you can implement this trait for closures too. If you want to do something with these errors, you can add trait bounds to them too. For example if these operations can time out and you want to report that using their error type, add where Self::Error: From<MyTimeoutError>.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.