So, I've been thinking more about supporting "break", "ret", and "cont" in all loops (including those implemented in library code). I originally proposed in #1619 a system that supported "break" and "cont" based on enums. But I was thinking that we could get a bit more ambitious and support ret and friends without undue difficulty. In addition, we could get better syntactic sugar to boot. There is nothing amazing in this proposal, the main new part is to repurpose the `for` loop to support the various bits of syntactic sugar needed to make iteration easy to use for the end user.

The basic return values would be:

    enum loop_ctl<T> { lc_break, lc_cont, lc_ret(T) }
    enum may_return<T> { mr_cont, mr_ret(T) }

So you would write something like vec::iter as:

    fn iter<T,R>(v: [T], f: fn(T) -> loop_ctl<R>) -> may_return<R> {
        let i = 0u, n = vec::len(v);
        while i < n {
            alt f(v[i]) {
                lc_break { break; }
                lc_ret(v) { ret mr_ret(v); }
                lc_cont { /* fallthrough */ }
            }
        }
        ret mr_cont;
    }

The main problem now is that if users write:

    vec::iter(v) {|i| ret foo; }

then they will ignore the return value, and so the ret will be lost.

To address this, we can repurpose the `for` loop form (or use a macro), so that you can write:

    for i in v { ... }

Here `v` can be any iterable thing, not just vectors. It's basically syntactic sugar for

    alt (v.iter { ...; cont; }) {
        mr_cont { /* fallthrough */ }
        mr_ret(v) { ret v; }
    }

Note that the compiler adds an implicit "continue" command at the end of the loop body. In addition, any `ret`, `break`, or `cont` statements which appear inside the loop body are translated into returns out of the closure that represents the body. This should then work fine for nested loops as well.

The main concern I can see would be Graydon's concern that writing all loops using an `alt` would impair performance or be a pain to use. I am not *so* concerned about it being a pain, a simple macro like:

    #macro[loop]{alt ... {
        lc_break { break; }
        lc_ret(v) { ret mr_ret(v); }
        lc_cont { /* fallthrough */ }
    }}

would cover most cases, I should think. (I don't actually know our macro syntax.) The performance would be worth experimenting with: I imagine that inlining will help and I can imagine LLVM-level optimizations to convert break/cont into their ideal equivalents, but if they don't exist it'd take some effort to write them.

Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to