Pre-RFC: `while let ... break`

The disagreement really is over how common this pattern is in relation to how exotic the syntax is.

Yes, you can do without for loops, but it is a very common pattern and it is well established in all imperative languages.

This pattern i have never come across, in my domain retry logic tends to be far more complicated and specified in an explicit FSM (if the robot arm did not reach the target point before the timeout triggered, do a recovery action, up to N times, but if the hydraulic pressure ever goes outside a specific range abort immediately). As such, simplistic retry like this just isn't useful. I also haven't seen this sort of pattern in any of the command line tools I have written.

Probably there is a domain where this is useful and common, but an RFC would need to motivate the need for the feature by demonstrating that, and that it is in fact useful across a broad number of domains, not just a single one.

2 Likes

Rust isn't Python. Rust is expression-based, which means the code you want can already be expressed, without the ambiguities of Python's for-else construct:

fn foo<T: PartialEq>(
    pred: impl Fn(&T) -> bool,
    iter: impl Iterator<Item = T>,
) -> Option<T> {
    let val = 'block {
        for val in iter {
            if pred(&val) {
                break 'block Some(val);
            }
        } 
        None
    };
    // do stuff with val
}

The specific function you wrote can be more clearly expressed both in Rust and in Python:

fn iter_find<T: PartialEq>(
    pred: impl Fn(&T) -> bool,
    iter: impl Iterator<Item = T>,
) -> Option<T> {
    for val in iter {
        if pred(&val) {
            return Some(val);
        }
    } 
    None
}
3 Likes

Library level solution that outputs 0 to 5:

use std::ops::ControlFlow::{self, *};

trait Repeat<Arg, Ret> {
    fn repeat(&mut self, arg: Arg) -> Ret;
}

impl<T, Arg, Ret> Repeat<Arg, Ret> for T
where
    T: FnMut(Arg) -> ControlFlow<Ret, Arg>,
{
    fn repeat(&mut self, mut arg: Arg) -> Ret {
        loop {
            match (*self)(arg) {
                Break(b) => return b,
                Continue(c) => arg = c,
            }
        }
    }
}

fn main() {
    let mut print_x = |i: i32| {
        println!("{i}");
        if i >= 5 {
            Break(())
        } else {
            Continue(i + 1)
        }
    };
    print_x.repeat(0)
}

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