[Pre-RFC] pseudo-closures

#1

Would it ever be possible for either of the following to be possible in the rust language because I feel that it could help with conciseness.

Example 1: returning from parent function in a “non-moveable” closure construct

fn foo (c_vec: Vec<C>) -> Result<Vec<D>, ErrorType> {
    c_vec.into_iter()
        .map('static |c| {
            if let Ok(d) = D::try_from(c) {
                d
            } else {
                return 'static ErrorType::new();
            }
        })
}

I know that the above example is a bit contrived but I have had instances in the past where something like this would have really help but instead I had to use other forms of iteration.


Example 2: using continue and break as “closures”

let list: Vec<Option<_>> = ...;
...
for item in list.iter() {
    ...
    foo.bar(item.unwrap_or_else(continue));
}

I know that it is possible to write the second as an if statement.

1 Like

#2

This post was flagged by the community and is temporarily hidden.

1 Like

#3

Can you find a non-contrived example? I know that Scala (as well as other languages) have non-local returns,so you may be able to find examples there.

Also,it’s not very clear what the first example means,it reads to me as doing a local return from the closure.

0 Likes

#4

The first example is doing a return either from the closure or from foo. Basically, it is trying to convert each item in the vector from a C to a D and if any fails then it returns some error from the outside function. The equivalent code in today’s rust is as follows:

fn foo (c_vec: Vec<C>) -> Result<Vec<D>, ErrorType> {
    let mut res = vec![];

    for c in c_vec {
        if let Ok(d) = D::try_from(c) {
            res.push(d);
        } else {
            return ErrorType::new();
        }
    }

    res
}
0 Likes

#5

Probably not, see

Same problem. Use try_fold instead of fold, and similar, instead.

2 Likes

#6

If the error types match,you can do this:

fn foo (c_vec: Vec<C>) -> Result<Vec<D>, ErrorType> {
    c_vec.into_iter()
        .map(|c| D::try_from(c) )
        .collect()
}

If the error types don’t match,you can add .map_err(|_| ErrorType::new() ) inside map.

2 Likes

#7

Maybe, but for sure it would incur a big penalty in terms of readability, exactly because it introduces non-locality.

1 Like

#8

A nice property of this style of “closures” is that they compose with control flow constructs, like ? or aync, nicely.

A good example here is Kotlin: because map,filter and friends for collections are implemented using “inline lambdas” (which are macros, semantics-wise), you can just call suspend functions from map over array list. Conversely, you can’t call suspend functions from mapping over lazy Sequences, because that uses a real lambda.

EDIT: to clarify, I don’t think we need this feature in Rust.

2 Likes

#9

What you’re suggesting are continuations (or rather, a subset of them), which I admittedly have been championing for in the long term. That said, any continuation mechanism that lands in Rust will have to have an answer to how they preserve local reasoning, which your suggestion is lacking.

1 Like

#10

I can do without them, but if they were to be added, I’d like some extra keywords to warn me, eg. mayret, topret, topbreak, topcontinue etc. or whatever:

Or maybe have labeled control flow, eg break :myLoopLabel, like some PLs have.

0 Likes