5

I cannot get the following code to compile.

  • I get an error that From is already implemented.
  • If I remove the manual impl of From I get the error that From is not implemented.
  • If I do not implement Error it works fine.

I suppose that this is due to the blank impl impl<T> From<T> for T in core. How should I work around this? Not implementing Error is not really an option.

Code (playground)

use std::fmt;
use std::io;
use std::error::Error;

#[derive(Debug)]
enum ErrorType {
    Other(Box<Error>)
}

impl fmt::Display for ErrorType {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str("not implemented")
    }
}

impl Error for ErrorType {
    fn description(&self) -> &str {
        use self::ErrorType::*;
        match *self {
            Other(ref err) => err.description(),
        }
    }
}

impl<E: Error + 'static> From<E> for ErrorType {
    fn from(other: E) -> Self {
        ErrorType::Other(Box::new(other))
    }
}

fn ret_io_err() -> Result<(), io::Error> {
    Ok(())
}

fn ret_error_type() -> Result<(), ErrorType> {
    try!(ret_io_err());
    Ok(())
}

fn main() {}

2 Answers 2

3

You don't.

That implementation would be a bit useless, anyway. It would mean that all other error types would just be immediately boxed. At that point, you might as well just make use of the existing conversions involving Box<Error> and use that instead.

If you want an error type that actually preserves the type of the unified errors, you'll need to implement From once for each of them. The error-type crate can help with defining unifying error types.

Sign up to request clarification or add additional context in comments.

4 Comments

Well, catching all Error is the whole point of such a generic implementation. Unfortunately there is no existing impl I can use. That would only work if I would always want to return Box<Error>. For now I use use map_err to wrap it at every call site.
@Ferio: The problem is that even if you could write that impl, it would immediately prevent you from ever implementing more specific logic for any other type. Your ErrorType enum would literally be the same as Box<Error>. You don't need to use map_err, you just need to write a From impl for every source error type, which is what error-type was designed for.
True…I didn’t consider how try! is implemented. Seems that a catch-all is not possible.
it wouldn't be literally the same, you can't impl foreign traits for Box<>
0

According comments above I've found this one approach works only:

impl<T: error::Error + 'static> From<Box<T>> for Error {
    fn from(e: Box<T>) -> Self {
        Error::Other(e)
    }
}

To use it you should Box errors:

try!(any_result().map_err(Box::new))

But if you need generic error (for user-defined tasks, as example) you don't need to wrap it with enum, try to use it directly:

trait AnyTask {
    fn do_it(&self) -> Result<Success, Box<Error>>;
}

It makes possible to use try! or .into() everywhere. This way:

fn do_it(&self) -> Result<Succeed, Box<Error>> {

    let row = try!(self.database.find_last());

    if row.some_condition {
        return Err("I don't like it!".into());
    }

    try!(self.database.insert(row));

    Ok(Success)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.