Swift Functional Programming Tutorial

Learn how to program in Swift using functional programming techniques, such as map and reduce, in this Swift functional programming tutorial. By Colin Eberhardt.

Leave a rating/review
Save for later
Share

Note from Ray: This is an abbreviated version of a chapter from Swift by Tutorials released as part of the iOS 8 Feast to give you a sneak peek of what’s inside the book. We hope you enjoy!

When making the transition from Objective-C to Swift, it’s logical to map concepts you know in Objective-C onto Swift. You know how to create classes with Objective-C, and now you know the equivalent in Swift. There are, of course, some completely new features, such as generics and range operators, but these are still little more than refinements of what you already know. (OK, perhaps not so little!)

However, Swift does more than provide a better syntax for your applications. With this new language, you have the opportunity to change the way in which you tackle problems and write code. With Swift, functional programming techniques become a viable and important part of your programming toolkit.

Functional programming can be a theory-heavy topic, so this tutorial will introduce the topic by example. You’ll work through a number of programming examples using what will likely be the more familiar, imperative style, and then try your hand at solving the same problems using functional techniques.

Note: This Swift functional programming tutorial assumes you already know the basics of Swift development. If you are new to Swift, we recommend you check out some of our other Swift tutorials first.

What is Functional Programming?

Briefly put, functional programming is a programming paradigm that emphasizes calculations via mathematical-style functions, immutability and expressiveness, and minimizes the use of variables and state.

Since there’s minimal shared state and each function is like an island in the ocean of your app, it makes things easier to test. Functional programming has also come into popularity because it can make concurrency and parallel processing easier to work with. That’s one more thing in your toolbox to improve performance in these days of multi-core devices.

Its time to put the fun- into functional programming!

Simple Array Filtering

You’ll start with something quite easy: a simple bit of math. Your first task is to create a simple Swift script that finds all the even numbers between 1 and 10 (inclusive). A pretty trivial task, but a great introduction to functional programming!

Filtering the Old Way

Create a new Swift playground file and save it wherever you like. Replace the contents of the newly created file with the following code:

var evens = [Int]()
for i in 1...10 {
  if i % 2 == 0 {
    evens.append(i)
  }
}
println(evens)

This produces the desired result:

[2, 4, 6, 8, 10]

(If you can’t see the console output, remember that you need to show the Assistant Editor via the View/Assistant Editor/Show Assistant Editor menu option.)

This little script is very simple; the key points of the algorithm are as follows:

  1. You create an empty (and mutable) array.
  2. The for loop iterates over the numbers from 1 to 10 (remember “…” is inclusive!).
  3. If the condition (that the number must be even) is met, you add it to the array.

The above code is imperative in nature. The instructions tell the computer how to locate the even numbers by giving it explicit instructions that use basic control structures, in this case if and for-in.

The code works just fine but the important bit—testing whether the number is even—is buried inside the for loop. There’s also some tight coupling, where the desired action of adding the number to the array is inside the condition. If you wanted to print each even number somewhere else in your app, there’s no good way to reuse code without resorting to copy-and-paste.

It’s fun-ctional time. (Sorry, I’ll stop it with the “fun” puns now!)

Functional Filtering

Add the following to the end of your playground:

func isEven(number: Int) -> Bool {
  return number % 2 == 0
}
evens = Array(1...10).filter(isEven)
println(evens)

You’ll see that the above, functional code creates exactly the same result as the imperative version:

[2, 4, 6, 8, 10]

Let’s look more closely at the functional version. It’s comprised of two parts:

  1. The Array(1...10) section is a simple and convenient way to create an array containing the numbers 1 through 10. The range operator 1...10 creates a Range you pass to the array’s initializer.
  2. The filter statement is where the functional programming magic takes place. This method, exposed by Array, creates and returns a new array that contains only the items for which the given function returns true. In this example, isEven is supplied to filter.

You’re passing in the function isEven as a parameter to filter, but remember functions are just named closures. Try adding the following, more concise version of the code to your playground:

evens = Array(1...10).filter { (number) in number % 2 == 0 }
println(evens)

Again, verify that the results from all three approaches are identical. The above example demonstrates that the compiler infers the type of the parameter number and return types of the closure from its usage context.

If you like your code to be as concise as possible, take it one step further and try the following:

evens = Array(1...10).filter { $0 % 2 == 0 }
println(evens)

The above uses argument shorthand notation, implicit returns, type inference… the works!

Note: The use of shorthand argument notation is a matter or preference. Personally, I think that for simple examples like the one above, shorthand notation is just fine. However, I’d opt for explicit argument names for anything more complicated. Compilers aren’t concerned with variable names, but they can make a world of difference to humans!

The functional version of this code is certainly more concise than the imperative equivalent. This simple example exhibits a few interesting features that are common to all functional languages:

  1. Higher-order functions: These are functions that you pass as arguments to other functions. In this simple example, filter requires that you pass a higher-order function.
  2. First-class functions: You can treat functions just like any other variable; you can assign them to variables and pass them as arguments to other functions.
  3. Closures: These are effectively anonymous functions you create in-place.

You may have noticed that Objective-C also exhibits some of these features through the use of blocks. Swift, however, goes further than Objective-C in promoting functional programming with a mix of more concise syntax and built-in functional abilities such as filter.

Colin Eberhardt

Contributors

Colin Eberhardt

Author

Over 300 content creators. Join our team.