Home > Software design >  How is this working? Do closures run implicit loops?
How is this working? Do closures run implicit loops?

Time:06-14

Trying to learn my way through Swift after doing some other languages. I'm following a course with some training challenges and such. At some point there's a challenge which solution is sort of this:

    for offset in offsets {
        if let matchIndex = expenses.items.firstIndex(where: {$0.id == expenses.bussinessItems[offset].id}){
            expenses.items.remove(at: matchIndex)
        }
    }

The thing I cannot get my head around is. What does $0.id mean? How does it get a different value each time and thus is compared with expenses.bussinessItems[offset].id in order for == to work?

Is the closure some sort of implicit for loop iterating over expenses.items? Why?

CodePudding user response:

expenses.items.firstIndex(where: { $0.id == expenses.bussinessItems[offset].id })

Is shorthand for this version which uses an explicit argument name

expenses.items.firstIndex(where: { expense in
  expense.id == expenses.bussinessItems[offset].id
})

which is a closure (AKA an anonymous function, or a block). To make it really clear, that's shorthand for

func expenseMatchesCurrentBusinessItem(_ expense: Expense) -> Bool {
   return expense.id == expenses.bussinessItems[offset].id
}

expenses.items.firstIndex(where: expenseMatchesCurrentBusinessItem)

Basically, it's a boolean function for checking if a given expense matches the one specified by the offset into the bussinessItems array. firstIndex(where:) accepts this function as its parameter and internally loops through its array calling that function with each element. If the provided function returns true, firstIndex(where:) returns the index for that element. Note that locally declared functions and closures have access to the variables declared in the same scope, which is how the function can access expenses and offset.

Once you get used to functional programming, that full example looks way too verbose. In general expenseMatchesCurrentBusinessItem is just "the function that tests if this is the thing we want" and its parameter expense is just "the thing in the array" so rather than name either of them, we use the unnamed anonymous closure syntax and the automatic argument name $0

  • Related