- Feature Name: result-pass
- Start Date: (fill me in with today’s date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Summary
Result currently provides no convenient way to convert between Results, even
if a conversion between the wrapped values is defined. This makes it much
more involved to pass on full Result values, then using try! or ? for
passing on plain error values.
This RFC suggests adding a method pass(), which converts Result<T,E>
into Result<U,F> if T: Into<U> and E: Into<F>.
Motivation
Consider the following code:
#[derive(Debug)]
enum ServerError {
IoError(std::io::Error),
// some more cases
}
impl From<std::io::Error> for ServerError {
fn from(e: std::io::Error) -> ServerError {
ServerError::IoError(e)
}
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
for stream in listener.incoming() {
let res = stream.map_err(ServerError::from)
.and_then(|mut s| {
handle(&mut s)
});
if let Err(e) = res {
println!("Error occured: {:?}", e);
}
}
}
fn handle(stream: &mut TcpStream) -> Result<(), ServerError> {
write!(stream, "hello!").map_err(ServerError::from)
}
Note the calls to map_err, which only provide trivial conversion
between errors. Finding this pattern is non-trivial and its application
unnecessarily repetitive.
While Result provides a lot of convenience methods to be combined,
it does not provide a trivial way to be converted into other Result,
even if implementors followed good practice and provide std::convert
implementations.
Similar arguments are apply for the T value.
Detailed design
Add a method pass to Result, with the following implementation:
impl Result<T,E> {
fn pass<U,F>(self) -> Result<U,F> where T: Into<U>, E: Into<F> {
self.map(T::into).map_err(E::into)
}
}
This allows easy, non-involved conversion between Result types that
have their std::convert story in order.
As T implies T: From<T>, this also neatly applies when the error
or the Result stay the same.
How We Teach This
This is a method addition that should come with its own documentation,
and additional documentation in std::result. An addition to the
error handling practices in the book can be considered.
Drawbacks
Result already has a big interface and this adds a method to it.
Alternatives
Implement From<Result<T,E>> for Result<U,F> where U: From<T>, F: From<E>.
This is more general, but possibly harder to discover, as the appropriate method to call would end up into().
Unresolved questions

: Is pass the best name?