Auto-implement `TryInto<U>` for `Option<T> where T: Into<U>`

It's important to preface this by saying that this change, although a convenient one, will most likely be a breaking change; this would overwrite some existing impls which would stop some programs/libraries from compiling. I think this is going to be the biggest reason that this never makes it into Rust, but I thought it was an idea worth discussing.

It's a simple convenience Impl; it could go something like

// Excuse the poor indentation and/or any
// errors; this is untested.
impl<T, U> TryInto<U> for Option<T> where T: Into<U> {
    type Error = Option<T>;

    fn try_into(self) -> Result<U, Self::Error> {
        if let Some(value) = self {
            value.into()
        } else {
            Err(self)
        }
    }
}

As you said, this formally conflicts with impl<T, U: TryFrom<T>> TryInto<U> for T, which can't realistically be removed. But even in practice, impl<T> From<T> for Option<T> already exists and that implies that your suggested impl would apply for U = Option<T>, generating an impl<T> TryInto<Option<T>> for Option<T>, which always succeed right now (due to impl<T> From<T> for T and a bunch of other impls) but fails with your proposal. Unfortunately to me all the impls already mentioned seem more intuitive and fundamental than the one you proposed.

1 Like

What does Error = Option<T> accomplish if it's always None?

3 Likes

Hm, maybe it should be Option<Infallible> based on the Try implementation of Option. Any idea why it isn't simply ()?

The desired conversion can be written pretty concisely as opt.map(Into::into) which is also very clear as to what exactly it is doing. (I'm intentionally ignoring the Result conversion, because usually it isn't useful to convert an Option<T> into a Result<T, SomeUnitType> just because.)

2 Likes