Functional Programming in Swift

Swift was introduced into the programming world in 2014. That was a turning point in software development for both macOS and iOS platforms. It brought more than a new programming language. It gave programmers a new way to write more efficient and less cumbersome codes.

This article focuses on one of the several features of this language: functional programming.

Functional Programming in Swift

What Is Functional Programming?

Functional programming is a coding technique. This technique focuses on using functions for software creation. It involves solving problems by first breaking complex processes into simpler ones known as functions.

Each function is designed to make it easier for programmers to avoid changing values or state beyond its scope. This is the opposite of Object Oriented Programming. That uses mutable data or shared state.

So, the programming technique uses declarations and expressions rather than statement execution. A functional program focuses on modularity. This involves treating mutable states carefully. Sometimes, using types to produce easy-to-test and maintain codes.

The use of rich types and simple function allows programmers to catch bugs while compiling a program. The bugs can then be fixed without waiting until it becomes a problem in production.

While object oriented programs are built on objects, functional programming uses functions.

Consider the differences between functional programming and object oriented programming:

Functional Programming Object Oriented Programming
1. It uses immutable data It uses mutable data.
2. It supports Parallel Programming It doesn’t support Parallel Programming.
3. Execution order of statements is not important. Execution order of statements is very important.
4. Its functions don’t have downsides. Its functions have many downsides.
5. It uses function calls and function calls with recursion for performing flow control. It uses conditional statements and loops for flow control process.
6. It focuses on what you are doing in your programming. The focus is on how you are doing your programming.
7. It supports Abstraction over Behaviour and Abstraction over Data. It only supports Abstraction over Data.

The two simple codes below will explain the differences between these programming concepts:

1. Iterative approach

//Imperative Approach
var numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for i in 0..<numbers.count {
let timesTen = numbers[i] * 10
numbers[i] = timesTen
}
print(numbers) //[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

2. Functional programming

//Functional Approach
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
extension Array where Element == Int {
func timesTen() -> [Int] {
    var output = [Int]()
    for num in self {
        output.append(num * 10)
    }
    return output
}
}
let result = numbers.timesTen()
print(numbers) //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(result) //[10, 20, 30, 40, 50, 60, 70, 80, 90, 100]

Note that both codes have the same output. But, the approaches are different. In the second code, the numbers array used is immutable. This is achieved with the “let” keyword.

To make it easier, a method was created to store the number multiplying process. This method is also stored on Array via an extension. In the process, the for…loop iteration statement is used while output, a variable, is updated. So, as you can see, the method holds the variable’s scope. It is limited to this.

Both codes perform the same function: multiplying all the numbers in an array by 10. In the first code, it is mandatory that you can only determine the result of the program by thinking like a computer. You must also go through the for…loop and follow the instructions.

In the code, you can see how the code gives the result. But, the functional approach hides how the result is achieved in a method. So, once you use the method in a different file, you can always have access to the method numbers.timesTen(). This explains what is achieved and not how it is done.

Functional programming has these peculiar features:

1. Immutable data

Immutability is a big concept in Swift. In this language, data structures are naturally immutable. This implies that a function has no power to change a program.

Swift allows programmers to explore the strength of this concept. With the rich value types and let keyword, it is easy for coders to avoid the mutable state.

Immutability makes cleaner code possible. So, the chances of bugs turning your code into a total mess are reduced. Such codes can be optimized by the compiler for better performance.

2. Modularity

Modularity is another concept that makes functional programming popular. It allows programmers to create small modules quickly. They can reuse the modules when necessary. This makes program development a lot easier and faster.

They can also test the modules as different entities. This reduces the amount of time spent testing and debugging a unit. In general, modularity simplifies programming.  

3. Referential Transparency

Referential transparency means that a programmer can replace functional program with its value. The replacement won’t have any impact on the program’s behavior.  Code reusability is the most important benefit of this attribute. It also doesn’t make data to be in a mutable state. This is helpful for programmers. In a mutable state, a function can yield two different results if it is called on two different occasions. Such abnormality overrules the ease of code test and maintenance.

4. First-Class Function

In Swift, functions are declared as first class type. This means functions are considered and treated as data, same as instances. Of classes and values are data too.

So, the language allows the programmer to pass such functions as arguments to other functions. Then, it must return the functions as values from where they are used. They can also assign the first-class functions to some other variables.

More so, they can be stored in data structures.

In programming languages, such as Swift, that have first class-functions, the functions are not treated as special. But, they can be used in other functions as outputs, like any other type can be used.

Inner functions can be defined inside a function under a special condition. This is only necessary if a very complicated logic needs to be broken down into simpler components.

Check this simple example of a first-class function:

// an old-school function

func hello() {

print(“Hello!”)

}

// it’s a block!

let hi: () -> Void = {

print(“Hi!”)

}

// this points to a function

let function = hello

// this is a copy of the closure

let block = hi

hello() // simple function call

function() // call through “function pointer”

hi() // simple closure call

block() // closure call through another variable

// closure parameter

func async(completion: () -> Void) {

// usually we’d do something here first…

completion()

}

// calling the method with a closure

async(completion: {

print(“Completed.”)

})

// trailing closure syntax

async {

print(“Completed.”)

}

5.  Closure

This is an inner function in Swift. It can have access to the variables of its parent’s function. This is irrespective of whether the parent function has executed or not. It shares some similarities with Lambdas in some programming languages and blocks in Objective-C and C.

When closures are defined within a context, they can capture any variables and constants. They can also store references to them within the context. This is commonly referred to as closing over the variables and constants.

Closures can be in any of these forms:

  • Nested functions: These are closure with a name. They can capture values within their enclosing functions. This is the simplest closure form that is capable of capturing values. It is usually embedded in another function. There, it can capture the arguments of its outer function. All variables and constants that are defined within the outer function are potential values it can capture.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {

var runningTotal = 0

func incrementer() -> Int {

runningTotal += amount

return runningTotal

}

return incrementer

}

The example above shows a function makeIncrementer. It contains incrementer, a nested function. Incrementer captures two values. These are amount and runningTotal, from the context surrounding it. makeIncreamenter returns incrementer as a closure after it has captured the values. Each time incrementer is called, it returns runningTotal by amount.

  • Global functions: Although these closures have a name, they don’t capture values.
  • Closure expressions: These are unnamed closures. They can take values from their surrounding context. They are usually represented with a lightweight syntax.

6. Maintainability

This feature ensures that programmers can maintain functional programming without much effort. As a result of the coding technique, you don’t have to worry about the possibility of changing any part of the program outside a specific function. So, you only change a program when there is a real need for such modification.

Functional Programming in Swift

Types of Swift Functions

Swift has several function types. They are used for different purposes in programs. The notable ones are:

1. Higher Order Functions

A function that can return from another function or can be passed to is known as higher order function. Functional programming is incomplete with these functions.

This is a typical higher order function:

// a function that takes another function as a parameter

func transform(value: Int, _ transformation: (Int) -> Int) -> Int {

return transformation(value)

}

let x = transform(value: 10) { value -> Int in

return value * 2

}

print(x)

// a function that returns another function

func increase(withMultiplication shouldMultiply: Bool) -> (Int, Int) -> Int {

func add(_ x: Int, _ y: Int) -> Int { return x + y }

func multiply(_ x: Int, _ y: Int) -> Int { return x * y }

return shouldMultiply ? multiply : add

}

let y = increase(withMultiplication: true)(10, 10)

print(y)

Swift has forms of the higher order function. These are Map, Filter, Sorted, and Reduce. They perform generic transformation that includes mapping elements to array. Using predicate to filter elements, and breaking a sequence down to a single value. Take a look at each one of them below:

  • Map: This is another very important higher order function. It takes a function from a program and applies it to array elements. In this code below, it squares the entire element of an array:

const numbers = [1,2,3,4,5,6,10,20];

const squares = numbers.map((x) => Math.pow(x,2)); // notice the lambda function : )

console.log(squares);

  • Filter: Filter is an array method. It accepts a test function as argument. This should return a Boolean. It will also return a new array populated with elements, only elements from the returned test function. This is an example of a filter that gets even numbers in an array:

function isEven(x){

  return x % 2 === 0;

}

const numbers = [12,324,213,4,2,3,45,4234];

const evenNumbers = numbers.filter(isEven);

console.log(evenNumbers);

Take a critical look at this code. The program can handle the arrays with the isEven function without any logic. So, the decision logic maintains its stand as a separate entity from the function. This makes it reusable, another beauty of higher order functions.

  • Reduce: This is the most powerful of all the different forms of higher order functions. This function accepts a callback function and is assigned a starting value. The value of the current array element and an accumulator serves as the arguments for the callback function. It then returns another accumulator. That will form the argument for the next callback function. Reduce returns a value that is the same as the one returned by the callback function.

Take a look at this code that filters even numbers only:

const isEven = (x) => {

  return x % 2 === 0;

}

const numbers = [12,324,213,4,2,3,45,4234];

const callback = (acc, x) => {

    if (isEven(x)){

     acc.push(x)

    }

    return acc

}

const evenNumbers = numbers.reduce(callback, []);

console.log(evenNumbers);

  •       Sorted: Sorted is a function that rearranges array elements. If a programmer calls sorted on an array, the result is a new array in ascending order. The effectiveness of this order depends on whether it conforms to a standard protocol: Comparable.

Consider this program:

Let numbers: [int] = [0,2,1,3,6,4,9,7,8]

Let ascendingNumbers = numbers.sorted()

 Print(numbers)

Print(ascendingNumbers)

Result: [0,2,1,3,6,4,9,7,8]

[0,1,2,3,4,6,7,8,9]

To specify the exact format you want to sort the array, use the sorted(by:)higher order function. An example is this:

Numbers.sorted(by: (Int, Int) -> Bool)

Note that this is a closure argument. But, you can define how the array of numbers should be sorted out within it.

This is an array of integers. So, Swift understands that the function for the program that will be used to pass an argument should be in this format (Int, Int). This represents type integer. For a string, the argument will take this form (String, String) ->Bool.

2. Generic Functions

You have a generic function when you try to give the higher order function a general role. Otherwise known as parametric polymorphism. This function type allows you to abstract the regular types.

Consider this:

// this only works for integers

func chooseInt(_ x: Int, or y: Int) -> Int {

return Bool.random() ? x : y

}

// whoa, this is a generic function

func choose<T>(_ x: T, or y: T) -> T {

return Bool.random() ? x : y

let x = chooseInt(1, or: 2)

print(x) // 1 or 2, but who knows this for sure

let y = choose(“heads”, or: “tails”)

print(y) // maybe heads or maybe tails

The example above shows how an integer type is abstracted away with a simple generic T type. You have the freedom to use anything for the generic type. What if the generic function with a string is the first parameter? Then, all other subsequent T types in the program will take the form of a string.

These attributes differentiate functional programming from the conventional coding method.

Functional Programming in Swift

Why Functional Programming?

The introduction of functional programming via Switch offers programmers tons of benefits. They include:

  • It reduces their vulnerability to making coding errors.
  • The codes are shorter with better modularity.
  • It supports effective use of Lambda Calculus. This is a framework that allows programmers “to study computations with functions.”
  • It increases developer’s productivity.
  • Parallel concurrency and processing.
  • Unit testing is easier to execute.
  • It focuses on process, not results.
  • It breaks problems into functions.
  • It doesn’t support conditional and loop statements.
  • It adopts mathematical functions. This concept uses recursion and conditional expressions for calculations.
  • It supports nested functions.

How Does Functional Programming Work In Swift?

Functional programming forms the core of Swift language. It allows programmers to write safe codes. These codes are usually written faster than before and are easy to maintain.

By default, Swift is immutable. So, that attribute has gone beyond its conventional use for collections. More so, variables are declared with the let keyword. The only exception is when semantics demand that the alternative keyword ‘var’ is used for the variable declaration.

Functional programming has eliminated or reduced the dependence on objects during coding. Most of the acceptable Swift types are values. These are String, number types, structs, enums, sets, arrays, and dictionaries.

Functions and classes are the only reference types. These attributes contribute to the natural ease of use of this programming language.

Functional programming has changed the way programmers handle projects. With Swift, coders can do their job with relative ease. They are less prone to errors than when using Object Oriented languages.

You can leverage the several features of functional programming. By doing so, programmers can work faster. Especially as coding becomes easier and cleaner, making them more efficient.

About the Author

admin

admin

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: