[swift-evolution] Remove forEach?

Sean Heber sean at fifthace.com
Tue Dec 8 14:21:05 CST 2015

It’d probably be confusing without a new keyword or symbol, but in the case of @noescape closures, maybe “return" could return from the outer scope instead of the inner one. Smalltalk has a distinction kind of like this.

In some ways, I think “return” should be reserved for actually returning from a *function* and “^” or something could exist for returning from a *closure* and that distinction would eliminate strange nested returns that sometimes crop up in these scenarios.

So as written, your example would just do the “right thing” if “return” was so defined. If you wanted to explicitly do the wrong thing, it could be written as:

    func indexOf_foreach(element: Element) -> Int? {
        self.indices.filter { idx in self[idx] == element }.forEach { idx in
            ^ idx
        return nil

If you tried to use “return” in an escaping closure, then it could be an error.


> On Dec 8, 2015, at 1:07 PM, Chris Eidhof via swift-evolution <swift-evolution at swift.org> wrote:
> Hi all,
> As long as the `for` loop is in the language, I don’t really see the use of `forEach`. I understand that it can read much nicer to write something like `a.map { something }.filter { somethingElse }.forEach {` rather than a `for` loop. However, I think the costs don’t outweigh the benefits. It might look like a for loop can just be replaced by a `forEach`, however, this is not true in the general case. For example, consider the following example:
>     func indexOf_foreach(element: Element) -> Int? {
>         self.indices.filter { idx in self[idx] == element }.forEach { idx in
>             return idx
>         }
>         return nil
>     }
> The code above (I realise it’s quite inefficient) might look like it’s returning the first index for which the filter’s condition returned true. However, the first occurrence of return is actually returning inside the closure, not the outer function. So the result of this function is always nil.
> Another solution would be to give a good warning/error message here (you’re trying to return an Optional value where we expect a ()). However, this is also problematic when dealing with side-effects. For example:
> [1,2,3,4,5].forEach { num in
>    print(num)
>    if num > 3 { return }
> }
> I think it’s quite easy to get things wrong with forEach, so I’d propose removing it and rather having a regular for loop. (Erica-style).
> Chris
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list