Converting errors with one extra level of indirection

I have a library that for the purposes of this question is called wrapper. wrapper has an App trait with an fn exec(&self) -> Result<(), Error> method (note Error means wrapper::Error here).

Applications implement App's exec() method and implement their regular application logic within it. The application has its own Error type as well. Clearly, the developer wants convenience converters, like allowing ? for error handling.

Here's a typical application implementation:

impl App for MyApp {
  fn exec(&self) -> Result<(), wrapper::Error> {
    std::env::current_dir()?;
  }
}

Uh-oh, spaghettios.. Orphan rule does not allow it [the application] to implement a From converter from std::io::Error to wrapper::Error.

I worked around this by splitting the implementation out:

impl App for MyApp {
  fn exec(&self) -> Result<(), wrapper::Error> {
    Ok(exec_inner()?)
  }
}

fn exec_inner() -> Result<(), Error> {
  std::env::current_dir()?;
}

.. because I implement From std::io::ErrorError, and Errorwrapper::Error.

There's no way to get Rust to understand that it can "chain" two error conversions together automatically, right? I.e. use the first code example, but Rust - through sheer will-power, and some magic, manages to realize that it can make it work by inserting another conversion? Well, now that I type it out I realize that it absolutely can not do that, and it's a spectacularly stupid question -- but since I typed it all out I'll post it anyway.

But I'll add: Is there another way to do this? To be honest this workaround does not horrify me, possibly because it also removes two levels of indentation, which always makes me happy. But I'm still curious if there's another way to do it, that's in the spirit of "Just stick a ? in there and magic will happen"?

No, Rust won't chain multiple From conversions. Often even trying that makes type inference ambiguous.

But there's map_err method that you can use to make it reasonably ergonomic:

exec().map_err(IntermediateErrorType::from)?
2 Likes

is this wrapper library written by you or is is a dependency? if it's your own library, you can change the App trait a bit, something like this:

pub trait App {
    type Error: Into<wrapper::Error>;
    fn exec(&self) -> Result<(), Self::Error>;
}
1 Like