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

Extended Try RFC #211

Closed
wants to merge 1 commit into from

Conversation

Projects
None yet
7 participants
@TyOverby
Copy link

TyOverby commented Aug 26, 2014

@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Aug 26, 2014

Have you read RFC PR #201?

@TyOverby TyOverby force-pushed the TyOverby:extended_try branch from c2bd19e to aa1ef53 Aug 26, 2014

@TyOverby

This comment has been minimized.

Copy link
Author

TyOverby commented Aug 26, 2014

Yeah, I saw that RFC and thought that the hidden layer of indirection isn't worth the lack of verbosity. Since they are both targeting the same problem, I'll close this one if #201 gets accepted.

@bill-myers

This comment has been minimized.

Copy link

bill-myers commented Aug 26, 2014

I don't think this is in conflict with #201.

Rather, it allows to handle cases when you want to wrap an error of the same type in multiple different ways, or in a non-default way, while #201 handles the default case automatically.

Both RFCs seem good to have.

Example:

enum MyError {
 MetadataIoFailed(IoError),
 DataIoFailed(IoError)
}

fn read_data_and_metadata(filename: &str) -> MyError {
 let index = try!(File::open(metadata_filename(filename)), MetadataIoFailed);
 let file = try!(File::open(filename), DataIoFailed);
 // do things
}
@lilyball

This comment has been minimized.

Copy link
Contributor

lilyball commented Aug 27, 2014

@bill-myers Hrm, that's actually a good point. I was thinking that #201 sufficed, because the resulting wrapper error type is used to figure out how to handle the underlying error, but that doesn't work for your example where MyError has two cases that both wrap an IoError.

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Aug 27, 2014

@TyOverby is the optional second argument restricted to always be an identifier? Or can it be an arbitrary expression (presumably any subtype of |: input: InputError| -> OutputError) ?

@TyOverby

This comment has been minimized.

Copy link
Author

TyOverby commented Aug 27, 2014

@pnkfelix : the idea would be that any element that is callable and typechecks would work. My macro-writing skills aren't up to par, but something like that should be feasible right? I will add this detail to the RFC later today; thanks for bringing it to my attention.

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Aug 27, 2014

@TyOverby it should be easy to write the appropriate macro (they can be declared as taking an expression or an identifier, among other syntactic classes); I just wanted to double-check about how general you expected this to be.

# Alternatives

* Create another macro that is very similar
* (named `try_or!` ?).

This comment has been minimized.

@nrc

nrc Aug 31, 2014

Member

Given that the try! macros is widely used and mostly liked, creating a new macro seems like it would be a much better idea. In that case, I would recommend implementing it as an external library and getting some use and experience, then submitting a PR to add it to std (I don't think that would require an RFC), and perhaps finally an RFC to add it to the prelude if it is very popular.

This comment has been minimized.

@lilyball

lilyball Aug 31, 2014

Contributor

@nick29581 The existing try!() can easily be extended to take two arguments without breaking any backwards compatibility. The suggestion for a new macro is only as a potential readability aid. Personally, I think using a new macro is unnecessary, providing a second arg to try!() should be visible enough.

This comment has been minimized.

@nrc

nrc Aug 31, 2014

Member

Its also a good way to get some experience using this without affecting a really crucial macro. I mean that if we added this, decided it was a mistake, then took it out again, it could be painful. So there is a high bar for acceptance. If we had some use of this beforehand to convince us it was a good idea, then it would be easier to accept.

So, change the last sentence in my previous comment to "submit an RFC to merge the new macro in with Try!"

This comment has been minimized.

@TyOverby

TyOverby Sep 1, 2014

Author

I wanted this macro bad enough that I made my own cargo project that implements this RFC.
https://github.com/TyOverby/try_or

I'm pretty bad at writing macros, so I wouldn't suggest that this be made the official implementation, but I've found that it is incredibly handy.

@TyOverby

This comment has been minimized.

Copy link
Author

TyOverby commented Sep 2, 2014

I just thought of another use of this macro: side-effectful error handling.

Imagine the following code:

enum MyError {
 MetadataIoFailed(IoError),
 DataIoFailed(IoError)
}

fn metadata_log(ioe: IoError) -> MetadataIoFailed {
    debug!("failed to get metadata with {}", ioe);
    MetadataIoFailed(ioe)
}

fn dataio_log(ioe: IoError) -> DataIoFailed {
    error!("data io failed with {}", ioe);
    DataIoFailed(ioe)
}

fn read_data_and_metadata(filename: &str) -> MyError {
 let index = try!(File::open(metadata_filename(filename)), metadata_log);
 let file = try!(File::open(filename), dataio_log);
 // do things
}

In this example, the failure in the try branch is logged before being transformed.

@reem

This comment has been minimized.

Copy link

reem commented Sep 2, 2014

I might be missing something obvious, but how is this better than just using the existing try! with map_err?

The previous example is just:

enum MyError {
 MetadataIoFailed(IoError),
 DataIoFailed(IoError)
}

fn metadata_log(ioe: IoError) -> MetadataIoFailed {
    debug!("failed to get metadata with {}", ioe);
    MetadataIoFailed(ioe)
}

fn dataio_log(ioe: IoError) -> DataIoFailed {
    error!("data io failed with {}", ioe);
    DataIoFailed(ioe)
}

fn read_data_and_metadata(filename: &str) -> MyError {
 let index = try!(File::open(metadata_filename(filename)).map_err(metadata_log));
 let file = try!(File::open(filename).map_err(dataio_log));
 // do things
}
@brson

This comment has been minimized.

Copy link
Contributor

brson commented Sep 5, 2014

Thank you for the RFC @TyOverby. At this time we're more inclined to go in the direction specified in #220, which is a fairly comprehensive overhaul of error handling that includes this functionality. In the meantime, this macro can be implemented by hand (with another name) for those that need the functionality.

Closing.

@brson brson closed this Sep 5, 2014

withoutboats pushed a commit to withoutboats/rfcs that referenced this pull request Jan 15, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.