Higher Order Functions: The Slick One !

A bit complicated, yet powerful never the less

Shubham Bakshi
May 20 · 7 min read
I have no idea what this image is doing here !

Well, it is one of those topics that every beginner finds hard to deal with and almost, every time, forget to use it in code. When i first saw Higher Order Functions in a code, to be honest, it seemed really stylish and fancy (That’s why the title — The Slick one !) . They are not that hard to understand , you just have to practice it and above all, remember to use it inside your code.

Before starting with Higher Order Functions, you should be aware of what closures are and how to use them. Worry not, I've got you covered. Checkout my article on Closure in Swift below ! You should not proceed without knowing closure syntax, shorthand properties and other stuff.

Back so early ? Nice ! Let’s get started .

Higher Order Functions are simply functions that take other function/closure as arguments or maybe even return a function/closure.

You can use Higher Order Functions with any Sequence say Array, Dictionary, Set etc. But for simplicity , in all our examples, we will use Array.

The three biggest stars under the banner are Map, Filter and Reduce . Out of these three , you will use the first two a lot. That doesn’t mean Higher Order Functions are just limited to these three, there are others like flatMap , compactMap, sort or sorted, contains, partition etc . Let’s start with the king of Higher Order Functions — Map.

Did someone said king ?

Map

If you look into the definition of it, you’ll find this —

func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]

I know, that’s a lot to take in. Let me break it down a bit.

  • This function , map, is a generic one.
  • The function take a closure/function as parameter named transform.
  • It works on the array provided to it, applies the transform(closure/function) to those array values, and returns a modified array

Now the key here is that the input Array and the output Array might not be of same type. Why so? If you look closely, we have two generics — Element and T . Element refers to the value inside the input array and T refers to the value of the output array. The reason we have two is that the closure/function that we provided as parameter to the map might mutate the value and create a different result type altogether(which is , in real world, the use case of map).

Enough theory, let’s dive into some code !

Let’s say we have to square all elements inside the array, we can either use a closure or a function , but i will use both !

Here, the type of input array and output array will be same , Int !

Using Closure as parameter to map

When we use map with closure, we need to use {} with map .

Using function as parameter to map

When we use map with function , we need to use () with map.

Don’t worry about the generic function , i have just used it for it to be more generic (pun intended). It can work without generic as well but then you have to make sure that the input array type and function’s input parameter type has to be same.

Yes I’m pretty sure about that !

But how does map really works ?

  • It takes the single element of the input array at a time, represented with $0
  • Modifies it according to the closure/function logic
  • Stores it inside the output array
  • Then the same for next and so on.

Let’s do a compairison

ta-da !!!!!

From here , i will not explain each Higher Order Function in detail, will give you a gist of how to use it and will leave it to you to do some magic and explore !

Filter

Filter definition looks something like this —

func filter<T>(_ isIncluded: (T) throws -> Bool) rethrows -> [T]

This is somewhat simpler . What it does is, the closure/function that we use as a parameter to filter method should return a Bool value indicating whether the input array value should be included in the output array. A true return value indicates that the array value should be included inside the output array.

If you noticed here, we have just one generic , T unlike 2 in case of map. What this means is that the type of input array and output array will be same as we are not modifying any input value, we are just deciding whether it should be included in the output array or not ! That’s the main difference between Map and Filter

Reduce

Reduce is somewhat less used but is equally important. It is useful in case where you want to collapse the whole sequence(array in our case) to just a single value, hence the name, Reduce .

func reduce<Result>(_ initialResult: Result, _ nextPartialResult: (Result, Element) throws -> Result) rethrows -> Result

Wow, That’s scary !

Don’t worry , all the function demands are two things :

  • An initial value upon which the initial computation will be performed (say added to , subtracted from and stuff).
  • A closure/function which will define the logic of what to do with the incoming values from the array and how to combine it into the value modified so far. The key here to note is that the closure will have two input parameters as compared to one we had so far. First will be the value that we have computed so far and second will be the input value from our array.

It’s a fairly simple example where we add all the elements of the array. Since we had 2 parameters to our function and the last one was a closure, we used the concept of trailing closure. And since we had 2 input parameter to out closure, we are using $0 and $1.

However, if all you want to do is sum all the elements, you can further reduce it down (pun intended) to —

let sumThemAll = Array(1…5).reduce(0,+)

FlatMap and CompactMap

These two Higher Order Functions are really confusing to some developers out there because prior to Swift 4.1 , there was only flatMap and no compactMap and flatMap used to perform the function of compactMap as well. If you want to check the motivation behind compactMap, check out this Swift Evolution Proposal.

What flatMap essentially does is , it flattens multiple arrays into one. First of, flatMap works for Array inside Array. It then combines all of those arrays into one.

What compactMap does is, it automatically remove any nil values from the array , which can be real handy if used correctly. Consider this, we have an array of String type and we want to convert them to Int . Using compactMap, it will automatically remove all those elements that cannot be converted to Int or in other words, which turns out to be nil while converting to Int.

Chaining Higher Order Functions

The true power of Higher Order Functions is unleashed when we chain different Higher Order Functions together to narrow down our lengthy code to a single line.

Wait, What ?

Let’s consider a scenario where we have two arrays inside an array of type String, we need to convert them all Int, square them all, and then add them all. Sounds complicated ? Well not exactly !

Conclusion

There are a few other Higher Order Functions as well but that’s for you to explore and try out yourself . I know it’s in our nature that whenever we see an array and we have to work with it, we always go for a for-in loop. But we have to break that habit.

Whenever we see a sequence (specially an array) and we have to mutate it and convert it to something else, always think of Higher Order Functions first. I know it’s a bit hard to get into the habit of using Higher Order Functions frequently but we have to as we have seen how much the amount of code gets reduced to.

That’s it folks ! Happy Coding !

You can connect with me on LinkedIn 👱🏻 or can get in touch with me via other channels 📬

Shubham Bakshi

Written by

iOS Engineer | Motivational Speaker enthusiast

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade