Can I implement the Into trait for using the `?` for error handling

I am trying to improve my error handling code and understand the ? operator.

I found this explanation that explains that this opertor automatically handles errors that have the into trait.

However when I implement the Into trait for my custom error type my error message says the From trait is not defined. I know that implementing the From trait also defines the Into trait but I don’t understand why I cannot directly implement the Into trait

As an example see this code.

pub trait MyError {
    fn detail(&self) -> String;
}

pub fn top_level() -> Result<(), Box<dyn MyError>> {
    let _user = fetch_user(2)?;
    Ok(())
}

struct UnknownUser;
impl MyError for UnknownUser {
    fn detail(&self) -> String {
        "what user".to_string()
    }
}

// This implementation works but replacing it with the Into implementation below is a compiler error.
impl From<UnknownUser> for Box<dyn MyError> {
    fn from(error: UnknownUser) -> Box<dyn MyError> {
        Box::new(error)
    }
}
// impl Into<Box<dyn MyError>> for UnknownUser {
//     fn into(self) -> Box<dyn MyError> {
//         Box::new(self)
//     }
// }

fn fetch_user(id: i32) -> Result<String, UnknownUser> {
    match id {
        1 => Ok("bob".to_string()),
        _ => Err(UnknownUser)
    }
}
1 Like

This has to do with the orphan rules, basically you can only implement a trait for your own types or you own trait for any type. There are some other rules, but they aren’t relevant.

The orphan rules are not a problem here; the impl is allowed because it is for a local type.

The problem is that the ? operator uses the From trait for conversion, not the Into trait.

Into is implemented automatically when you implement From, but the reverse is not true, so it’s almost always better to implement From.

Huh, I wasn’t aware of that. Do you know why that is the case? Looking at the original RFC for ?, it says that ? should use Into. Is it because the try macro used From?

Yes, as far as I can tell the implementation of the question mark operator copied from the existing try! macro rather than from RFC 243.

1 Like

The book description of the unstable Try trait also claims to use Into:

The ? operator allows interconversion between different Try implementers only when the error type can be converted Into the error type of the enclosing function (or catch block).

Ah, there’s an issue:

3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.