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() {}
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.
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)
}
Related
What is the recommended way of propagating different error types in Rust (especialy when their definition doesn't merge)?
The Scenario
Initially, I was curious about how to stop a running thread in Rust. Search suggests it goes through channel communication + conditional.
So, I came up with this code which (1) should loop 5 iterations, (2) with 500 ms sleep in-between iterations, and (3) will stop right after the third iteration.
use std::any::Any;
use std::sync::mpsc;
use std::sync::mpsc::SendError;
use std::thread;
use std::time::Duration;
fn main() -> Result<(), Box<dyn Any + Send>> {
fn some_condition(i: i32) -> bool { 3 == i }
thread::spawn(|| -> Result<(), SendError<bool>> {
let (tx, rx) = mpsc::channel::<bool>();
for i in 0..5 {
if some_condition(i) { tx.send(true)? }
if let Ok(true) = rx.try_recv() { break }
println!("i = {}", i);
thread::sleep(Duration::from_millis(500));
}
Ok(())
}).join()?; // Result<(), SendError<bool>>
// I get away with a warning: which the expected compiler behaviour
Ok(())
}
The Problem
While this code run with the expected behaviour, I have a warning for not using the result resulting from the ? error propagation.
So I was tempted to do ?? instead of just ?. But then, I got the following compiler warning error:
error[E0277]: `?` couldn't convert the error to `Box<dyn Any + Send>`
--> src/main.rs:44:53
|
27 | fn main() -> Result<(), Box<dyn Any + Send>> {
| ------------------------------- expected `Box<dyn Any + Send>` because of this
...
44 | }).join()/*.map_err(|error| Reference(error))*/??;
| ^ the trait `From<SendError<bool>>` is not implemented for `Box<dyn Any + Send>`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<Box<(dyn std::error::Error + 'a)> as From<E>>
<Box<(dyn std::error::Error + 'static)> as From<&str>>
<Box<(dyn std::error::Error + 'static)> as From<Cow<'a, str>>>
<Box<(dyn std::error::Error + 'static)> as From<String>>
and 22 others
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, SendError<bool>>>` for `Result<(), Box<dyn Any + Send>>`
Then I realised it is because Box<dyn Any + Send> and From<SendError<bool>> are not overlapping types... And, the first propagation match the former type and the second, the latter.
So I suspect from here that the problem could be phrased as: [H]ow to define overlapping types for such use cases?
Envisioned Solution
Intuitively, I tried adding this code that fails (as expected):
// Only traits defined in the current crate can be implemented for arbitrary types [E0117]
impl From<SendError<bool>> for Box<dyn Any + Send> {
fn from(_: SendError<bool>) -> Self {
todo!()
}
}
However, wrapping errors under the same type solves the issue.
Adding:
use crate::Error::{Reference, Source};
#[derive(Debug)]
enum Error {
Reference(Box<dyn Any + Send>),
Source(SendError<bool>)
}
impl From<Error> for SendError<bool> {
fn from(_: Error) -> Self {
todo!()
}
}
impl From<SendError<bool>> for Error {
fn from(_: SendError<bool>) -> Self {
todo!()
}
}
Then, changing lines to match
// ...
tx.send(true).map_err(|error| Source(error))?;
// ...
}).join().map_err(|error| Reference(error))??;
Bottom Line
It works but is so verbose that I's like it for Rust to have another way (something in the likes of Infallible, maybe).
What is the recommended way of propagating different error types in Rust (especialy when their definition doesn't merge)?
The idiomatic way depends on whether you're writing a library or an application.
For applications, you usually use some dyn Trait as you just need to display the error.
Usually you don't use dyn Any for errors in Rust but dyn std::error::Error which is a trait for... well, errors. It contains things like (optional, unstable currently) backtrace, error chain and description via Display. Or sometimes you use a crate like anyhow, which is basically a better wrapper for std::error::Error.
The problem is that join() returns std::thread::Result that has an error type Box<dyn Any + Send>. This is because it does not represent "just" error, but a panic (that possibly occurred in the spawned thread) - and panic payload is always Box<dyn Error + Send>. Usually you just unwrap() this to propagate the panic to the spawning thread, but if you want to convert it to a dyn Error, you cannot since there's no way to convert dyn Any to dyn Error.
The way I would tackle this is by creating a wrapper, PanicError, that wraps Box<dyn Error> and implements std::error::Error:
#[derive(Debug)]
pub struct PanicError {
pub payload: Box<dyn Any + Send>,
}
impl From<Box<dyn Any + Send>> for PanicError {
fn from(payload: Box<dyn Any + Send>) -> Self {
Self { payload }
}
}
impl fmt::Display for PanicError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self.payload.downcast_ref::<&'static str>() {
Some(&msg) => msg,
None => match self.payload.downcast_ref::<String>() {
Some(msg) => msg,
None => "Box<dyn Any>",
},
};
f.pad(msg)
}
}
impl Error for PanicError {}
Then you can use it like:
.join()
.map_err(PanicError::from)??;
For libraries, you want to give maximum flexibility to the consumers. They should be able to print the error, but also to match the specific type of error occurred. The usual way to do that is by creating an enum with variant for each possible error, a From implementation from each internal error to its variant (so you can use ? to propagate errors), and Display and Error implementations. You don't need to write this by hand: there are crates such as thiserror that will help you. I would still use the PanicError wrapper, though, as it is easier to work with:
#[derive(Debug, thiserror::Error)]
pub enum MyError {
#[error("a thread panicked: {0}")]
Panic(
#[source]
#[from]
PanicError,
),
#[error("failed to send close signal")]
CloseSignalSendingFailure(
#[source]
#[from]
SendError<bool>,
),
}
fn main() -> Result<(), MyError> { ... }
I'm trying to simplify the error flow in a webapp I'm working on, and my plan was to make a struct that implements std::error::Error and just forwards the result of description() for whatever kind of error it's wrapped around. I've implemented From for the types of errors I want to wrap, so this struct makes it easy to use try! to get a uniform error result. Here's what I have so far for the struct:
#![feature(convert)]
use std::error::{Error};
use std::fmt::{self,Display,Formatter};
use std::io::{self,Read};
use std::ops::Deref;
use std::fs::{File};
#[derive(Debug)]
pub struct StrErr{
desc:String,
c: Option<Box<Error>>
}
impl StrErr{
pub fn new(msg:String) ->Self{
StrErr{desc:msg, c:None}
}
}
impl Error for StrErr{
fn description(&self) -> &str{
self.desc.as_str()
}
fn cause(& self) -> Option<& Error> {
self.c.map(|e| e.deref())
}
}
impl Display for StrErr {
fn fmt(&self, f:&mut Formatter) -> Result<(),fmt::Error> {
f.write_str(self.desc.as_str())
}
}
impl From<io::Error> for StrErr {
fn from(o:io::Error) -> Self {
StrErr{desc: String::from(o.description()),c:Some(Box::new(o))}
}
}
fn main(){
let contrived = Some("foo.txt")
.ok_or_else(|| StrErr::new(String::from("error message")))
.and_then(|filename| Ok(try!(File::open(filename))))
.and_then(|mut file| {
let mut content = String::new();
try!(file.read_to_string(&mut content));
Ok(content)
});
if let Ok(content) = contrived {
println!("Got content: {}", content);
} else {
println!("got an error");
}
}
playground
The problem is with the cause() method - I can't return a reference to the inner Error instance because e doesn't live long enough. Is there a different way I can structure this so that I can keep the generic reference to anything that implements Error (which I currently do by putting it in a Box) but I can still fully implement the Error trait (which is expecting a ref to the parent Error)?
I've worked around it by just punting on cause() and having it return None, but I'd much rather conform to the intent of the trait.
rustc 1.2.0-nightly (613e57b44 2015-06-01) (built 2015-06-02)
This is one way you can convert an Option<Box<Trait>> to an Option<&Trait>. I'm avoiding all of the trait implementation to clearly show the interesting code:
use std::error::Error;
pub struct StrErr {
c: Option<Box<Error>>
}
impl StrErr {
fn cause(&self) -> Option<&Error> {
self.c.as_ref().map(|e| &**e)
}
}
fn main() {}
We use Option::as_ref to avoid consuming the self.c item. The map closure is provided with a &Box<Trait>, so we dereference it twice to get to a Trait, and then reference it once to get to a &Trait.
I would like a function that accepts a variety of types that can be converted to my specific type. In similar cases, I'd use std::convert::Into (or std::convert::From):
pub struct MyThing;
impl<'a> Into<MyThing> for &'a str {
fn into(self) -> MyThing {
MyThing
}
}
fn main() {}
As an extra wrinkle, in my specific case, the conversion can potentially fail. Normally, I'd use Result to represent an operation that may fail. Combining the two concepts together:
pub struct MyThing;
pub struct Error;
impl<'a> Into<Result<MyThing, Error>> for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
Unfortunately, this seems to run afoul of coherence rules:
error: the impl does not reference any types defined in this crate;
only traits defined in the current crate can be implemented for
arbitrary types [E0117]
I see that I could create my own specific trait:
struct MyThing;
struct Error;
trait IntoMyThing {
fn into(self) -> Result<MyThing, Error>;
}
impl<'a> IntoMyThing for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
Or even a more-generic trait:
struct MyThing;
struct Error;
trait MaybeInto<T, E> {
fn into(self) -> Result<T, E>;
}
impl<'a> MaybeInto<MyThing, Error> for &'a str {
fn into(self) -> Result<MyThing, Error> {
if self.len() % 2 == 0 {
Ok(MyThing)
} else {
Err(Error)
}
}
}
fn main() {}
But is there any way to reuse components from the standard library to accomplish my goal?
This isn't possible as-is due to coherence rules, which makes things like this pretty inconvenient, because you can't do it unless you create a newtype for one of the types, either the Result or the &str. See RFC #1023 for more information.
In short, based on the new rules stipulated by that RFC, you cannot implement a trait that's not local to the crate for a type that's not local to the crate.
Modify the orphan rules so that impls of remote traits require a local type that is either a struct/enum/trait defined in the current crate LT = LocalTypeConstructor<...> or a reference to a local type LT = ... | < | &mut LT.
So since you didn't create the Into trait in your crate nor the Result type, you get this error. Creating a new type fixes this because it basically wraps a non-local type in a local type.
I am trying to print an Option<Box<MyStruct>>, but I get a compile error when trying to implement Display for Option<Box<MyStruct>>.
use std::fmt;
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{}", maybe_my_struct);
}
struct MyStruct {
foo: i32,
}
impl fmt::Display for Option<Box<MyStruct>> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
Some(MyStruct) => write!(formatter, "{}", self.foo),
None => write!(formatter, "No struct"),
}
}
}
The error I get is :
error: the impl does not reference any types defined in this crate;
only traits defined in the current crate can be implemented for arbitrary types [E0117]
I have tried aliasing the Option type, and instead implementing Display for MyOption<Box<MyStruct>>, but that gives the same result. What am I doing wrong?
As you can see, you can't implement a trait you didn't write for a type you didn't write. This is part of what's known as "coherence" and exists to prevent really weird things like linking against a library suddenly causing unrelated parts of your program to change behaviour.
Aliasing Option to MyOption doesn't work either because, as you say, it's an alias. That is, it's just another name for the same thing, it's not an actual, different type.
Now, if you write a wrapper around Option like so:
struct MyOption<T>(Option<T>);
then MyOption will be a new, distinct type that you can implement a trait for. Of course, you'll want to write methods to wrap and unwrap the actual Option you're storing.
... But this is all rather irrelevant since you could also just derive Debug for your struct and use that.
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{:?}", Some(maybe_my_struct));
}
#[derive(Debug)]
struct MyStruct {
foo: i32,
}
Or, if you really want the custom display logic for the Option<Box<MyStruct>> combination, you can use a marker value (this same approach is used by Path in the standard library, incidentally). Like so:
use std::fmt;
fn main() {
let maybe_my_struct: Option<Box<MyStruct>> = Some(Box::new(MyStruct{foo:42}));
println!("{:?}", maybe_my_struct);
// Instead of displaying directly, display via a custom marker.
println!("{}", maybe_my_struct.display());
println!("{}", None::<Box<MyStruct>>.display());
}
#[derive(Debug)]
struct MyStruct {
foo: i32,
}
// This is the marker we'll use to define our custom Display impl.
struct MmsDisplay<'a>(&'a Option<Box<MyStruct>>);
// This trait lets us extend Option<Box<MyStruct>> with a new method.
trait CustomMmsDisplay {
fn display<'a>(&'a self) -> MmsDisplay<'a>;
}
impl CustomMmsDisplay for Option<Box<MyStruct>> {
fn display<'a>(&'a self) -> MmsDisplay<'a> {
MmsDisplay(self)
}
}
// And here's the display logic.
impl<'a> fmt::Display for MmsDisplay<'a> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match *self.0 {
Some(ref ms) => write!(formatter, "{}", ms.foo),
None => write!(formatter, "No struct"),
}
}
}
I want to use my customised error type in all functions and I need to wrap the existing standard errors so that the ? operator will succeed.
Here is what I am doing:
use std::{error::Error, fmt, fs};
#[derive(Debug)]
enum MyError {
A,
B,
}
impl fmt::Display for MyError {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl Error for MyError {
fn description(&self) -> &str {
""
}
}
trait NotMyError {}
impl<T: NotMyError + Error> From<T> for MyError {
fn from(_: T) -> MyError {
MyError::A
}
}
fn test() -> Result<(), MyError> {
fs::read_dir("test")?;
Ok(())
}
fn main() {}
The compiler complains:
error[E0277]: the trait bound `std::io::Error: NotMyError` is not satisfied
--> src/main.rs:30:5
|
30 | fs::read_dir("test")?;
| ^^^^^^^^^^^^^^^^^^^^^ the trait `NotMyError` is not implemented for `std::io::Error`
|
= note: required because of the requirements on the impl of `std::convert::From<std::io::Error>` for `MyError`
= note: required by `std::convert::From::from`
There's an excellent post about it. To get first-class support for your error you need to do two things:
Implement the Error trait for your type.
Implement std::convert::From for error types you want to use seamlessly with the ? operator (the quick_error crate helps automate this).