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