Should all collections implement Try?

Hi, I often find myself writing this:

fn get(a: usize) -> Option<Vec<u32>> {
    ...
}
fn foo(a: usize) -> Vec<u32> {
    get(a)?
}

and expecting ? to return a Vec::default() from foo.
But this doesn't work, because foo's return type does not implement Try.
This makes me think, is there a reason why not all Default types should implement Try, when there is an obvious way to implement it?

impl<T> Try for Vec<T> {
    type Ok = Self;
    type Error = NoneError;

    #[inline]
    fn into_result(self) -> Result<Self, NoneError> {
        if !self.is_empty() {
            Ok(self)
        } else {
            Err(NoneError)
        }
    }

    #[inline]
    fn from_ok(v: Self) -> Self {
        v
    }

    #[inline]
    fn from_error(_: NoneError) -> Self {
        Self::default()
    }
}

Maybe impl<T: Default> Try for T is not possible due to downstream conflicts, but still any standard Default types could implement it.

(Note: Returning Vec<u32> from get directly is not always possible, for example for HashMap::get)

That wouldn't help in your example, you're using ? on an Option, which does implement Try. The error message is a bit misleading.

I don't think solving your example is really the point of your post, but for completeness, this works:

fn foo(a: usize) -> Vec<u32> {
    get(a).unwrap_or_default()
}

Yes, the problem with this is that it does not have the same behavior as ? when there are other statements after the tried one. It would have to be

fn foo(a: usize) -> Vec<u32> {
    let v = get(a).unwrap_or_default();
    print!("Done");
    v
}
// vs
fn foo(a: usize) -> Vec<u32> {
    get(a)?;
    print!("Done");
}

? seems to require the return type to implement Try aswell. This works: Rust Playground

1 Like

I don't think you really want Default here -- that includes things like i32 which gets into the controversial "is zero falsey" conversation, and libs has already expressed skepticism about ?-on-bool.

You could maybe argue it on Vec (following https://en.wikipedia.org/wiki/Monad_(functional_programming)#Collections), but even then what you're actually doing in the example is interconversion, of which I'm generally not a fan in ?.

1 Like

Yes, I thought about that too, it doesn't map Default perfectly, but it should be justified for collections.