Introduction to Functional Programming in Swift
Swift is a multi-paradigm programming language developed by Apple for creating applications for iOS, macOS, watchOS, and tvOS. In addition to object-oriented and protocol-oriented approaches, Swift actively supports functional programming. This style is based on using pure functions, data immutability, and avoiding side effects.
Functional programming makes code more predictable, testable, and concurrency-safe. In this article, we will break down the key concepts of the functional approach in Swift: immutability, higher-order functions, closures, and method chaining. You will see how to write concise and expressive code using map, filter, and reduce.
Fundamentals of the Functional Approach in Swift
Immutability
In functional programming, data is not modified after creation. Instead of changing an existing object, a new one is created. Swift encourages this approach with the let keyword for declaring constants.
// Immutable valuelet numbers = [1, 2, 3, 4, 5]// numbers.append(6) // Compilation error — numbers is immutable
// Creating a new arraylet newNumbers = numbers + [6]print(newNumbers) // [1, 2, 3, 4, 5, 6]Using let instead of var helps avoid accidental state changes and simplifies debugging.
Functions as First-Class Citizens
In Swift, functions are first-class citizens. They can be assigned to variables, passed as arguments, and returned from other functions.
// Function assigned to a variablelet multiply: (Int, Int) -> Int = { $0 * $1 }print(multiply(3, 4)) // 12
// Function that takes another functionfunc applyOperation(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int { return operation(a, b)}
let result = applyOperation(10, 5, operation: multiply)print(result) // 50Closures in Swift
Closures are self-contained blocks of functionality that can capture and store references to variables from their surrounding context. In Swift, closures are widely used for callbacks and functional transformations.
// Simple closurelet greeting = { (name: String) -> String in return "Hello, \\(name)!"}print(greeting("World")) // Hello, World!
// Shorthand form with parameterslet numbers = [3, 1, 4, 1, 5, 9]let sorted = numbers.sorted { $0 < $1 }print(sorted) // [1, 1, 3, 4, 5, 9]Closures make code compact and expressive, especially when working with collections.
Higher-Order Functions: map, filter, reduce
These are the three pillars of functional programming in Swift. They allow processing arrays, dictionaries, and other collections without explicit loops.
map — Transforming Each Element
The map method applies a closure to each element of a collection and returns a new array with the results.
let prices = [100, 200, 300, 400]let discounted = prices.map { $0 * 0.9 }print(discounted) // [90.0, 180.0, 270.0, 360.0]
// Working with stringslet names = ["Anna", "Boris", "Victor"]let uppercased = names.map { $0.uppercased() }print(uppercased) // ["ANNA", "BORIS", "VICTOR"]filter — Selecting by Condition
filter returns a new array containing only the elements that satisfy a given condition.
let scores = [45, 78, 92, 33, 88, 61]let passingScores = scores.filter { $0 >= 60 }print(passingScores) // [78, 92, 88, 61]
// Filtering stringslet words = ["Swift", "iOS", "macOS", "function"]let shortWords = words.filter { $0.count <= 4 }print(shortWords) // ["iOS", "macOS"]