Using ? on Option<T> in method without return type

I want to be able to use the ? operator to return early from a method with no return type, if the Option contains None.

Compare these three:

fn do_if_not_none(maybe_none: Option<u32>) {
    let definitely_u32 = match maybe_none {
        Some(exists) => exists,
        None => return,
    };
    do_things_with_u32(definitely_u32);
}

fn do_if_not_none(maybe_none: Option<u32>) -> Option<u32> {
    do_things_with_u32(maybe_none?);
    None
}

fn do_if_not_none(maybe_none: Option<u32>) {
    do_things_with_u32(maybe_none?);
}

They look decently similar in this highly simplified case but the first two can quickly grow, especially with multiple Option variables.

I understand why this wouldn't be great for Result - error swallowing should be explicit. Is there a reason this can't exist for Option?

You can use an Option<!> return type, that makes it zero-cost.

8 Likes

This will be kinda possible with either try blocks (playground example) or custom Try implementations (playground example)

This could also be written with the new let else expression:

fn do_if_not_none(maybe_none: Option<u32>) {
    let Some(definitely_u32) = maybe_none else { return };
    do_things_with_u32(definitely_u32);
}

(Playground)

Using a try block would be a clear winner here if it did not require a type annotation. This is called out as the last open concern in the tracking issue.

6 Likes

Yeah, sadly the try version right now is

#![feature(type_ascription)]
#![feature(try_blocks)]

fn do_if_not_none(maybe_none: Option<u32>) {
    (try {
        do_things_with_u32(maybe_none?);
    }: Option<_>);
}

which is really not fun.

1 Like

why not using .map?

fn main(){
    do_if_not_none(Some(2));
    do_if_not_none(Some(3));
    do_if_not_none(None);
}

fn do_if_not_none(maybe_none: Option<u32>) {
    maybe_none.map(do_things_with_u32);
}

fn do_things_with_u32(a: u32) {println!("{}",a)}
1 Like