When to use forEach(_:) instead of for in?

SwiftLoopsForeachSequenceFor in-Loop

Swift Problem Overview


As documented in both Array and Dictionary forEach(_:) Instance methods:

> Calls the given closure on each element in the sequence in the same > order as a for-in loop.

Nevertheless, adapted from Sequence Overview:

> A sequence is a list of values that you can step through one at a > time. The most common way to iterate over the elements of a sequence > is to use a for-in loop.

Implying that iterating sequence by forEach(_:) or for in:

let closedRange = 1...3

for element in closedRange { print(element) } // 1 2 3

closedRange.forEach { print($0) } // 1 2 3

Or (Array):

let array = [1, 2, 3]

for element in array { print(element) } // 1 2 3

array.forEach { print($0) } // 1 2 3

Would gives the same output.

Why forEach(_:) even exist? i.e what is the benefit of using it instead of the for in loop? would they be the same from performance point view?

As an assumption, it could be a syntactic sugar especially when working with functional programming.

Swift Solutions


Solution 1 - Swift

There is no performance benefit offered by forEach. In fact, if you look at the source code, the forEach function actually simply performing for-in. For release builds, the performance overhead of this function over simply using for-in yourself is immaterial, though for debug builds, it results in an observable performance impact.

The main advantage of forEach is realized when you are doing functional programming, you can add it to a chain of functional calls, without having to save the prior result into a separate variable that you'd need if you used for-in syntax. So, instead of:

let objects = array.map { ... }
    .filter { ... }

for object in objects {
    ...
}

You can instead stay within functional programming patterns:

array.map { ... }
    .filter { ... }
    .forEach { ... }

The result is functional code that is more concise with less syntactic noise.

FWIW, the documentation for Array, Dictionary, and Sequence all remind us of the limitations introduced by forEach, namely:

> 1. You cannot use a break or continue statement to exit the current > call of the body closure or skip subsequent calls. > > 2. Using the return statement in the body closure will exit only from > the current call to body, not from any outer scope, and won't skip > subsequent calls.

Solution 2 - Swift

I recently ran across a use case where using forEachwas preferable in a tangible way to for in. Let's say you want to remove all sublayers from a layer. A statement such as the below doesn't work as you need to unwrap the [CALayer]

for layer in self.videoContainerView.layer.sublayers!

If sublayers are nil, you will get a crash. This forces you to check to see if there are sublayers first. However, a forEach makes this much simpler as in the following:

self.videoContainerView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }

Solution 3 - Swift

They are more or less interchangeable, but there are two important differences.

  1. break/continue only work in a for .. in
  2. return in forEach will exit the closure, but will not halt the iteration.

The reason for this is that for .. in is a special form in the language (which allows break and continue to work as you expect). It is something that you can't implement in an identical way using the language itself.

However, forEach is not a special form and can be re-implemented identically by writing it as a function.

extension Sequence {
    func myOwnForEach(_ body: (Self.Element) throws -> Void) rethrows {
        let it = Self.makeIterator()
        while let item = it.next() {
            body(item)
        }
    }
}

Solution 4 - Swift

In addition to above answers one more reason that differentiates for loop from forEach is that with for loop we can also chose to implement that logic using where based pattern matching instead, like

for adBanner in adBanners where !adBanner.isLoading {

The above kind of control flow related features are what makes for loops so powerful, but if we don’t need that level of control, using a call to forEach might give us slightly simpler-looking code.

So in short using a for loop gives us a much greater degree of control over an iteration

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAhmad FView Question on Stackoverflow
Solution 1 - SwiftRobView Answer on Stackoverflow
Solution 2 - SwiftC6SilverView Answer on Stackoverflow
Solution 3 - SwiftplinthView Answer on Stackoverflow
Solution 4 - SwiftRahul SerodiaView Answer on Stackoverflow