Swift Functional Programming: Basic Concepts

Kinda like reverse Fight Club for developers

Usually people that learn functional programming (also known as FP) don’t shut up about it, to a point where it would almost be irritable if it just wasn’t so darn cool. Imagine the famous scene of the 1999 classic cult movie Fight Club, but completely flipped on its head.

Rules of Functional Programming Club:

1. You do not shut up about Functional Programming.

2. You do NOT shut up about Functional Programming!

Some people also liken functional programmers to Crossfit enthusiasts, but unlike Crossfit, functional programming doesn’t have a 73.5% chance of you sustaining an injury preventing you from working. It actually improves the safety, readability and general awesomeness of the code you write.

Swift is by no means a purely functional programming language such as Haskell, but instead it’s more of a beautiful Frankenstein/multi-paradigm language by taking bits and pieces of other languages and making them cohesive with one another.

In this first part, we’re going to look at the simpler concepts of functional programming and demonstrate how the Swift language enables us to write functional code.

Basic Concepts

Immutability

let foo = 1

The easiest to understand, immutability simply means that once a value is set it cannot be changed, and we do this in Swift using the let keyword when creating values.

The reason for immutability is because it allows us as developers to write thread-safe code. We can work with objects knowing with complete certainty that other threads within our application cannot change values as we are using them.

Value types

struct CGRect { }

When we pass around values instead of references to values, we create safer code. Structs are a great example of this too, pretty much everything inside the Swift standard library is a struct: Array , Dictionary , Int , Bool , and so forth, are all structs.

The reason why they’re safer than references is because when they’re passed around and used to set other objects, they’re copied on assignment which figuratively prevents rug from being pulled out from underneath us. Let me help you understand this concept with some code:

var box = CGRect.zero

var square = box.size box.size.height = 10 // square: width: 0, height: 0

// box.size: width: 0, height: 10

If CGRect and CGSize were reference types instead of value types, square ’s height would have also changed to 10 when we changed box ’s height.

box.size.height = 10 // square: width: 0, height: 10

// box.size: width: 0, height: 10

Pure functions

func sum(_ a: Int, _ b: Int) -> Int {

return a + b

}

A function where its return value is only determined by its input value/s, without any observable side-effects. It does one thing, and only one thing which is compute its return value, nothing else.

Even if we place a log inside the sum() function, that would make it an impure function, which very contagious when writing code.

So basically the idea of writing pure functions is to eliminate all possibilities of side-effects which can increase the chance for bugs, and yes, this includes logging too.

First-class functions

func sayHello() {

print("Hi!")

} let greeting = sayHello greeting() // prints: Hi!

In its creation, the Swift overlord creators decided in all their might to make almost everything a first-class citizen. When functions are said to be first-class, it means that we can assign functions to variables, just like we would with, say, an Int or String .

This allows us to write functions that can take other functions as arguments as well as return them, so that we may pass them around to other parts of our code.

Higher-order functions

Because functions are considered first class, that means we’re able to create “higher-order” functions. For a function to be considered higher-order, it must abide by at least one of the following two traits:

Use a function as an argument

Return a function

To illustrate an example of this, let’s create a higher-order function that accepts another function as an argument:

func inside() -> Void {

print("Yo!")

} // inside's structure:

// () -> Void

We have a function named inside that takes no arguments and returns nothing, otherwise known as Void . In the comment underneath it, I’ve described the function’s structure, which is very important to understand. The structure is what the compiler will analyse to validate compatibility when passing it into other functions as arguments. Now let’s see a function that accepts another function as an argument:

func outside(inner: () -> Void) {

inner()

}

As you can see, our outside function takes one argument, which is also another function. If you look at inner argument’s type, you can see it has the same structure as our inside function. Because both the inside function and the inner argument’s parameters are the same, we are able to pass inside into inner and the compiler won’t say a peep or burst into flames.

Finally, we call the inner parameter from within the outside function and it will in turn call the print() function that was in inside ’s body:

outside(inside)

// prints: Yo!

Advanced Concepts

Chaining, Composition and Currying

We’ve only just begun scratching the surface of functional programming in Swift, there is still a lot to cover with the next few parts of this ongoing series of posts, of which will include some more advanced concepts such as the three C’s above. They’re a bit complex so each will probably get its own post, but hopefully by now you have an improved understanding of how Swift incorporates the basic parts of the functional programming paradigm to make your code more robust, safer and versatile.

In saying that, I would like to formally welcome you to the Functional Programming Club. Please remember to practice Rules 1 & 2 as you gleefully await the next part of this series.