Conversion to anyhow

I had my own error type, with lots of conversions to it. It was too non-standard and didn't do error propagatin, so I started to convert to "anyhow". (Good choice?)

So I tried this conversion, modeled on something I was doing with my own error type. I want to be able to convert errors of the form Result<something, &'static str>. But Rust does not allow this conversion.

use anyhow;
impl std::convert::From<&'static str> for anyhow::Error {
    fn from(msg: &'static str) -> Self {
        anyhow::anyhow!("{}",msg) 
    }
}

Error message is:

error[E0119]: conflicting implementations of trait `std::convert::From<&'static str>` for type `anyhow::Error`:
  --> src/common/errors.rs:17:1
   |
17 | impl std::convert::From<&'static str> for anyhow::Error {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `anyhow`:
           - impl<E> From<E> for anyhow::Error
             where E: std::error::Error, E: Send, E: Sync, E: 'static;
   = note: upstream crates may add a new impl of trait `std::error::Error` for type `&'static str` in future versions

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
  --> src/common/errors.rs:17:1
   |
17 | impl std::convert::From<&'static str> for anyhow::Error {
   | ^^^^^--------------------------------^^^^^-------------
   | |    |                                    |
   | |    |                                    `anyhow::Error` is not defined in the current crate
   | |    `str` is not defined in the current crate
   | impl doesn't use only types from inside the current crate
   |
   = note: define and implement a trait or new type instead

So is it possible to define an implicit conversion from str to anyhow::Error?

2 Likes

This is the purpose of the anyhow! and bail! macros.

2 Likes

Yes. where my code generates the error. But where something being called is returning Result<something, &'static str>, and the enclosing function wants Result<something, anyhow::Error>, conversion is needed. How do I set up such conversions?

You could use anyhow::Error::msg to convert a string to an anyhow::Error. You have to do the mapping explicitly, though:

fn foo() -> Result<(), &'static str> { Err("oops") }

fn bar() -> Result<(), anyhow::Error> {
    foo().map_err(anyhow::Error::msg)?;
    Ok(())
}
2 Likes

OK, that works. Not as elegant as I'd hoped, but not too hard to convert.

Rust needs a unified error story. Python went through this. In early Python, errors could be any type and were usually strings. Then Python got a standard error hierarchy and all errors had to be subclasses of items in the official hierarchy. It helped.

After a few unsuccessful attempts, I'm now starting to appreciate thiserr.

At first it felt intimidating. Possibly because I felt like I needed to define every error I might run into up front. In my most recent attempt (in progress), I started with thiserr's example and will change/add errors as I encounter the need for them. Having an error.rs file helps me flip back and forth easily :slight_smile:

I've also used more than one enum. One enum per
important module/struct seems to be working ok. Now I can match on a specific error if I like, or just use anyhow in an application. The specific errors help with debugging while writing the lib! I have so far caught one error by testing which errors my code produced and getting a surprise!

I have to say having witnessed (from afar) the churn in the error handling story since error-chain and failure, I'm happy to stick with anyhow and thiserr for a good while. The error trait has been improved in this time and I think we're in a good place now.

anyhow seems fine. It's the lack of standardization that causes problems, not the functionality. If all library crates that used Result used the same error type, or at least something that converted to a standard error type, life would be easier.

This is one of the two things I've encountered in Rust that come in too many incompatible versions. The other is small vectors and matrices, 2D, 3D, and 4D. I'm using external crates which force me to have three different incompatible sets of those. A headache for game and graphics work.

1 Like

This is what the std::error::Error trait is for: everybody implements Error for their error types, and you can use dyn Error as a catch-all type that any library error can be converted into. anyhow itself is just a wrapper around Box<dyn Error> that makes it simpler to use directly.

(A library that uses &'static str for its errors is not respecting this convention.)

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.