[swift-evolution] Remove forEach?

Kevin Ballard kevin at sb.org
Wed Dec 9 13:12:17 CST 2015


On Wed, Dec 9, 2015, at 09:43 AM, Matthew Johnson via swift-evolution wrote:
> 
> >>>>> Another direction you might take this is to make it a type annotation on the function type, like throws, so forEach has a type like this:
> >>>>> 
> >>>>> func forEach(body: (Element) breaks -> ())
> >>>>> 
> >>>>> and a closure that `breaks` has nonlocal behavior for break/continue/return (and is implied to be noescape and void-returning, I guess).
> 
> I missed this post the first time around.  Is a really great idea and is something I hoped we might get eventually.  It allows "control flow" functions to behave as expected.
> 
> I assume a caller could pass a non-breaking closure if desired just as we can pass a non-throwing closure if desired, right?
> ,
> How would break and continue interact with the caller of the closure?  It would need to implement the correct behavior of skipping to the next loop cycle or moving on to any post-loop logic.
> 
> How would this behave for a closure that is stored and called later, possibly asynchronously?  Or would it only be allowed on closures declared

The idea is interesting, but I share your concerns, and Guillaume's concern about labelled breaks as well.

I'm inclined to say that making things like for-in as a library feature instead of a language feature may be more easily accomplished with macros, as that bypasses all these questions (since it will get rid of the closure). Note that a for-in loop could be easily transformed by a macro into the following:

Source (for let):

[label:] for [var] pattern in sequence [where condition] {
    body
}

Result (for let):

[label:] do { // to scope the generator
    var gensymmedName = sequence.generate()
    while letOrVar pattern = gensymmedName.next() [where condition] {
        body
    }
}

Source (for case):

[label:] for case pattern in sequence [where condition] {
    body
}

Result (for case):

[label:] do { // to scope the generator
    var gensymmedName = sequence.generate()
    while let gensymmedName2 = gensymmedName.next() {
        if case pattern = gensymmedName2 [where condition] {
            body
        }
    }
}

-Kevin Ballard


More information about the swift-evolution mailing list