[swift-evolution] Remove forEach?

André Videla zephyz at me.com
Tue Dec 8 16:18:31 CST 2015


Hi, 

As I understand it, the argument for remove forEach is that it’s easy to make confusing code that doesn’t do what it looks like it should do.

In this particular example:

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

I think the compiler should give us two warnings:
- closure returns type Int when it should return type ()
- function always return nil (which is a unit type just like () ) when it expects Option<Int>

In my opinion those warnings should be enough to make the programmer aware that this code doesn’t do what it looks like it does. Typically, returning a type when () is expected shouldn’t go silently.

As such I think keeping forEach is important as it allows for every elegant expressions and convey already the already established convention when you use forEach that “I”m only interested in side-effects with elements in this collection”

My proposition is then that instead of removing forEach, we should have better type check and warn when the cardinality of the expected type and the returned type don’t match.

-André

> On 08 Dec 2015, at 20:07, 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151208/8d158719/attachment.html>


More information about the swift-evolution mailing list