Pre-RFC: attempt! macro

I often find myself tired of typing

let something = match something {
    Ok(ok) => ok,
    Err(_) => {
        eprintln!("Oh no, something failed D:");
        eprintln!("Try taking a glass of water and trying again!");
        return;
    }
};

.

I love match in general, but for errors it’s just so much boilerplate for so little. I often just make an attempt macro:

macro_rules! attempt_or {
    ($result:expr, $fail:block) => {
        match $result {
            Ok(ok) => ok,
            Err(_) => {
                $fail
            }
        }
    }
}
let something = attempt_or!(something, {
    eprintln!("Oh no, something failed D:");
    eprintln!("Try taking a glass of water and trying again!");
    return;
});

This works, but it’s boring to rewrite that macro for every single project. Also, it doesn’t give us access to the err variable.

It would be absolutely amazing to have a macro like this (but better) built in to the STD, for simply extracting a value while still giving complete control over the error.


Thoughts?


EDIT: Another problem with this macro is that you have to return or break or similar, otherwise it complains about incompatible match types.

This macro inhabits the same design space as the guard let ... else pattern, but is less expressive (as it limits itself to Tryable things?). Check out this RFC: https://github.com/rust-lang/rfcs/pull/1303 It was postponed, but I think that many people would like to see that pattern in Rust, so the idea isn’t dead.

2 Likes

If your main goal is to describe the error, then I suggest

let something = something.map_err(|_| Error("oh noo"))?;

With error_chain or custom error type you can make it ergonomic to add context.

1 Like

I’d very much prefer to customize it more than that…

If we could figure out a clean way to support an outer return this pattern would fall out naturally.

let something = something.unwrap_or_else(|| {
    eprintln!("Oh no, something failed D:");
    eprintln!("Try taking a glass of water and trying again!");
    
    // return from captured fn (other syntax ideas were proposed in the thread)
    // I like this one the best as it resembles break labels
    return 'fn;
});

I opened an internal thread on that here: pre-RFC: Allow return, continue, and break to affect the captured environment

1 Like

I assume that would only apply to FnMut, right?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.