I frequently find myself writing something like the following:
let value = loop {
match fallible_function() {
Ok(value) => break value,
Err(e) => {
// Some form of retry logic, log message, exponential back-off
},
}
};
// Do something with the value
To me, this screams that it should be a while let loop, since I'm looping on one pattern until I get the other pattern. The only problem being that I need to get the Ok result out, which a while let does not allow. Thus, I propose the following syntax:
while let Err(e) = fallible_function() break Ok(value) {
// Some form of retry logic, log message, exponential back-off
}
// Do something with `value` which is now bound
Generally, the idea is that if the let bind doesn't match the output of the function, then we bind whatever pattern follows the break in the current namespace after the loop. Combined, the two patterns need to be able to match any pattern the value can have, so we can apply the break bind to whatever was checked.
I think it's probably also best to disallow break statements in a while let ... break loop. There's probably some way to make it work, but it seems too complicated and hard to implement/explain/understand to be worth any possible use.
Anyone have any thoughts about this? Especially, I can't decide if it's better to use break as the keyword (is how one normally returns a value from a loop) or if it should be replaced with else (is normally how one indicates something is done if a condition doesn't hold), or if something else entirely should be done.
I also can't decide if it's better to bind the name from the pattern in the surrounding namespace, or to require the pattern have exactly one new identifier and have the loop evaluate to that value, which would turn the example above into this:
let value = while let Err(e) = fallible_function() break Ok(value) {
// Some form of retry logic, log message, exponential back-off
};
// Do something with `value` which is now bound