Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Exception to Error. #113

Closed
wants to merge 7 commits into from
Closed

Conversation

richard-uk1
Copy link

And use anyhow::Error rather than Box<dyn Error+...>.

fixes #86 .

And use `anyhow::Error` rather than `Box<dyn Error+...>`.
@ghost
Copy link

ghost commented Nov 24, 2019

What is the reason for re-exporting the error type from anyhow rather than wrapping it in a new type?

@dtolnay
Copy link

dtolnay commented Nov 25, 2019

Ditto -- you want this wrapped in your own type.

@richard-uk1
Copy link
Author

@dtolnay do you mean like this?

@richard-uk1
Copy link
Author

Since a boxed trait object is 'static by default, I could remove all the annotations in examples, if that was wanted.

@yoshuawuyts
Copy link
Member

@derekdreery replacing the custom error types in the examples with this new error type would be v. welcome!

@richard-uk1
Copy link
Author

richard-uk1 commented Nov 27, 2019

@yoshuawuyts

replacing the custom error types in the examples with this new error type would be v. welcome!

I can do this, but I would argue that we don't need to. The user of this crate (e.g. the examples) can use whatever error system they like - they are not tied to using surf::Error, and IMO it's good to demonstrate this in the examples.

src/error.rs Outdated

impl Error {
/// Use this when you need to implement middleware, where the error type must be `surf::Error`.
pub fn new<E>(error: E) -> Self
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this constructor private or pub(crate).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally did this, but I found that the user needed to be able to create surf::Errors in the middleware examples. I'll have a look to see if this can be avoided.

src/error.rs Outdated
}
}

impl Deref for Error {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not idiomatic to implement Deref and DerefMut on error types - only smart pointers should implement those traits.

@ghost
Copy link

ghost commented Nov 27, 2019

In the examples, this is a little bit verbose:

async fn post_json() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    // ...
}

We could simplify with:

type Error = Box<dyn std::error::Error + Send + Sync>;

async fn post_json() -> Result<(), Error> {
    // ...
}

Btw, I think it'd also be nice to have this in the crate so that surf::Result<T> becomes a thing :)

type Result<T> = std::result::Result<T, crate::Error>;

@richard-uk1
Copy link
Author

I've been looking at using a boxed error in middleware rather than surf::Error, but I run into a problem converting Box<dyn std::error::Error + Send + Sync> into a anyhow::Error. Is this possible? I would imagine not, since trait object representation is not stable (e.g. see rust-lang/rfcs#2594 for recent work).

Otherwise the options are to make Middleware take an Error assoicated type, or to allow users to create surf::Errors.

Other suggestions welcome!

@dtolnay
Copy link

dtolnay commented Nov 27, 2019

but I run into a problem converting Box<dyn std::error::Error + Send + Sync> into a anyhow::Error. Is this possible? I would imagine not

anyhow! will do that conversion.

use anyhow::{anyhow, Result};

fn f() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    Err(Box::from("oh no!"))
}

fn main() -> Result<()> {
    match f() {
        Err(err) => Err(anyhow!(err)),
        Ok(_) => unreachable!(),
    }
}

@richard-uk1
Copy link
Author

Cool! I've included that, so that the middleware can take any boxed error. It could still be switched to an associated type if people think that would be better. I've used an alias for boxed errors where it's hidden from the user to make the code less verbose, but where the user sees it I've always used the original type rather than an alias.

Copy link
Member

@yoshuawuyts yoshuawuyts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this patch is now defining custom BoxErrors in all examples; I'd like us to use surf::Error or surf::Result instead. This way people can learn about Surf's Error type.

Also CI failing because of missing cargo fmt. Would you mind running that? Thanks heaps for the work you've put in!

src/error.rs Outdated
@@ -0,0 +1,59 @@

use std::{fmt::{self, Display, Debug}, ops::{Deref, DerefMut}};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this not be nested. Thanks!

fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.0.source()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're missing From<Error> impls here also.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be From<Error> impls for the log errors and the io errors in the next_reuse example?

// The need for Ok with turbofish is explained here
// https://rust-lang.github.io/async-book/07_workarounds/03_err_in_async_blocks.html
fn main() -> Result<(), surf::Exception> {
fn main() -> Result<(), BoxError> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use surf::Error here?

@@ -118,7 +118,7 @@ And even creating streaming proxies is no trouble at all.
```rust
use async_std::task;

fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use surf::Error here?

impl<C: HttpClient> Middleware<C> for Printer {
fn handle<'a>(
&'a self,
req: Request,
client: C,
next: Next<'a, C>,
) -> BoxFuture<'a, Result<Response, surf::Exception>> {
) -> BoxFuture<'a, Result<Response, BoxError>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use surf::Error here?

impl<C: HttpClient> Middleware<C> for Doubler {
fn handle<'a>(
&'a self,
req: Request,
client: C,
next: Next<'a, C>,
) -> BoxFuture<'a, Result<Response, surf::Exception>> {
) -> BoxFuture<'a, Result<Response, BoxError>> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use surf::Error here?

@richard-uk1
Copy link
Author

This is out of date so I'm gonna close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

surf::Exception does not implement std::error::Error
4 participants