





















































MobilePro #185: Swift Made Simple—Functional Programming Demystified
Hi ,
Welcome to the 185th edition of MobilePro!
This week we’re leaning into a topic that quietly supercharges Swift codebases: Functional Programming (FP). If you’ve ever wrestled with tricky state, mysterious side effects, or concurrency gremlins, FP gives you a set of habits that tame complexity without sacrificing performance or readability.
Our feature article, adapted from Mastering Swift 6 by Jon Hoffman, cuts past theory and zeroes in on four core principles you can apply today:
You’ll see how each concept maps naturally onto common iOS patterns (networking pipelines, view model transformations, and collection handling), and how small shifts, like returning new values instead of mutating in place, lead to predictable behavior, safer concurrency, and easier testing.
Before we jump in, let's take a quick look at last week's highlights:
Staying sharp in .NET takes more than just keeping up with release notes. You need practical tips, battle-tested patterns, and scalable solutions from experts who’ve been there. That’s exactly what you’ll find in .NETPro, Packt’s new newsletter, with a free eBook waiting for you as a welcome bonus when you sign up.
Jon Hoffman has over 30 years of experience in the information technology field. Over the years, he has worked in system administration, network administration and security, application development, and architecture. He currently serves as an Enterprise Software Manager for Syntech Systems.
Outside of his professional life, Jon has a wide range of personal interests that keep him both physically and mentally engaged. He enjoys spending quality time with his two children and his fiancée. He also stays active through running, hiking, paddleboarding, yoga, and working out. In addition, Jon has a deep passion for reading and continues to nurture his love for coding.
Functional programming is a programming paradigm that views programs as collections of mathematical functions and avoids changing data or states. While Swift is primarily a protocol-oriented language, it offers support for functional programming concepts.
Functional programming is based on several fundamental principles, and in this article, we will explore five of the most important principles, starting with immutability.
Immutability is a key concept of functional programming that helps make code more reliable and easier to understand. Basically, immutabilitymeans that once we create a piece of data, we can't or don’t change it. Instead of modifying the original data, we create a new version of the data with the changes.
This is different from other programming paradigms where data can be changed or modified frequently, which can lead to unexpected errors and harder-to-track bugs. By preventing data from changing, we ensure that our code behaves in a predictable way, making it easier to track down bugs and other issues with our code.
Immutability also makes it safer to run parts of our program in a concurrent environment, because we don't have to worry about one part of our application changing data that another part is using. Overall, embracing immutability in functional programming leads to cleaner, more robust, and maintainablecode.
Let’s look at a code example to illustratethe concept of immutability with Swift:
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
In this example, we begin by defining a constant that holds an array of numbers. Using constants instead of variables is critical for maintaining immutability because, once defined, a constant cannot be changed. When we want to double each number in the array, rather than updating the original array, a new constant is created that contains the new values.
Pure functions are a fundamentalconcept in functional programming, and they play a critical role in writing reliable and maintainable code. A pure functionis one that, given the same input, always produces the same output and has no additional side effects. This means that pure functions do not modify any external state or depend on an external state, ensuring that their behavior is predictable and consistent.
The use of pure functions brings several advantages to functional programming. They make code easier to understand because each function operates independently of external factors. Pure functions also simplify testing and debugging since they can be tested in isolation without considering the broader application state. Furthermore, they enable safer concurrent execution, since the lack of side effects eliminates the risk of one part of the application interfering with another.
Let’s look at a basic example of a pure function:
func add(_ first: Int, _ second: Int) -> Int {
first + second
}
let total = add(2,4)
In this example, we define a function that takes two arguments and returns the sum of the values. The function operates solely on its input parameters, adding the two values together and returning the result without altering or relying on any external state. This makes the function a pure function, as it produces the same output given the same inputs and has no side effects.
First-class functions are another key concept in functional programming. They enable us to treat functions as first-class citizens, which means they can be assigned to variables, passed as arguments to other functions, and returned from other functions, just like other data types.
First-class functions enable support of keyfunctional programming techniques such as currying and function composition. These techniques help us create a more modular and maintainable code base by breaking down complex operations into simpler, reusable components.
Let’s look at a basic example of how a first-class function works. In this example, we will begin by creating the following two functions:
func add(_ first: UInt, _ second: UInt) -> UInt {
first + second
}
func subtract(_ first: UInt, _ second: UInt) -> UInt {
first - second
}
first + second
}
let total = add(2,4)
The first function, add(), will add two numbers together and return the results, while the second function, subtract(), will subtract the second number from the first and return the result. What is key to realize about these two functions is that they have the same function signature where they each accept two unsigned integers and return an unsigned integer ((UInt, UInt) -> UInt).
One of the concepts of first-class functions is the ability to assign them to variables or constants. The following example shows how we could do this:
let mathFunction = add
let result = mathFunction(8, 4)
In this example, we create aconstant named mathFunction and assign the add() function to it. We then use the mathFunction constant to add two numbers together. Alternatively, we could have assigned the subtract() function to the mathFunction constant to subtract the numbers. If mathFunction were a variable instead of a constant, we could change which function is assigned to it at any time.
Higher-order functions are another key concept in functional programming and significantly improve the flexibility andreusability of our code. A higher-order function is one that can take other functions as arguments, return functions as the result, or both. This enables us to write more abstract and modular code by creating functions that operate on other functions.
In functional programming, higher-order functions enable powerful techniques such as function composition, where complex operations are built by combining simpler functions.
As an example, we will use the same add() or subtract() function that we created in the First-class functions section and create a function that accepts either of these two functions as an argument:
func performMathOperation(_ first: UInt, _ second: UInt,
function: (UInt, UInt) -> UInt) -> UInt {
function(first, second)
}
In this example, notice that the third argument of the performMathOperation() function, named function, accepts a function with the same functional signature as the add() and subtract() functions, which is (UInt, UInt) -> UInt. Then, within this function, we call the function that was passed in, returning the result. We could then use the performMathOperation() function like this:
let result = performMathOperation(8, 4, function: subtract)
In this example, we call the performMathOperation() function, passing in the subtract() function as the third argument. After this code is run, the result constant will have a value of 4. (If we had passed in the add() function, the value of the result constant would have been 12.)
Swift includes several higher-order functions that are commonly used. Some examples of these are the map(_:), filter(_:), reduce(::), and forEach(_:) functions.
By embracing immutability, pure functions, first-class functions, and higher-order functions, Swift developers can unlock the strengths of functional programming. These principles not only lead to more reliable and bug-resistant code but also foster cleaner design and easier scalability.
Functional programming may require a shift in mindset, but the payoff in clarity, safety, and maintainability makes it well worth the effort.
If you want to dive deeper into the latest Swift 6.2 and build powerful, maintainable apps, then Jon Hoffman's Mastering Swift 6 is the book for you!