Paradigms

Imperative

In the imperative approach, we have a sequence of instructions that describe step by step how the program’s state is modified.

Let’s look on the example ⤵️

var value = 0

func increment() {
    value += 1 // Mutating the state
}

print(value) // 0
increment()
print(value) // 1

In the code we have a mutable variable value and a function increment that mutates the state (value). We first print the initial value, then increment it, and finally print the updated value.

Simple, right? Let’s jump into functional programming!

Functional

What is functional programming? Is it only about writing functions? 🤔

Not really.

Of course, functions are a foundation of functional programming, but they need to follow an important rule ⤵️

In functional programming, functions must not have side effects.

What’s the side effect? - A side effect occurs when a function modifies any state outside of its own scope.

Looking at the imperative programming example, we can clearly see a side effect inside the increment function ⤵️

var value = 0

func increment() {
    value += 1 // Mutating the state (Side effect)
}

print(value) // 0
increment()
print(value) // 1

How can we re-shape this code to align with functional programming principles? - we need to get rid of state mutation both from main program flow and inside the increment function.

Let’s fix the function first by passing the state (value) as an argument and returning the result of the operation as function’s output.

var value = 0

func increment(_ value: Int) -> Int {
    value + 1
}

print(value) // 0
value = increment(value)
print(value) // 1

Now, increment is a pure function. It returns a new state by adding 1 to the input without mutating any external state. To manage state changes in functional programming, we create new values instead of modifying the old state.

Having pure functions always returning the same output for a given input makes them easier to test and debug.

Now we focus on mutability which functional programming aims to avoid. Instead of mutating the state - value, we transform the old state and return a new one.

The code refactored to the functional form ⤵️

func increment(_ value: Int) -> Int {
    value + 1
}

let initialState = 0
let incrementedState = increment(initialState)

print(initialState) // 0
print(incrementedState) // 1

By adding the increment method as an extension to Int, we can use method chaining to apply multiple transformations in a clean, readable way. This is a common practice in functional programming, known as function or method composition ⤵️

extension Int {
    func increment() -> Int {
        self + 1
    }
}

let initialState = 0
let incrementedState = initialState
    .increment()
    .increment()

print(initialState) // 0
print(incrementedState) // 2

Functional Reactive

functional reactive programming is a paradigm that combines functional programming with publisher and subscriber pattern. It emphasises streams of events carrying data that can be transformed along the way to the subscriber. FRP enables better handling of concurrency and asynchronous operations, making code more expressive.

If we’d like to showcase the above example using FRP, it would look something like this ⤵️

var incrementSubject = PassthroughSubject<Void, Never>()
var valueSubject = CurrentValueSubject<Int, Never>(0)

let disposableStream = Publishers.CombineLatest(incrementSubject, valueSubject)
    .map { _, value in value + 1 }
    .subscribe(valueSubject)


print(valueSubject.value) // 0
incrementSubject.send()
print(valueSubject.value) // 1

Final Thoughts

Having a deeper understanding of FRP, beyond just describing use cases like observing keyboard input to trigger requests, can truly make you stand out in an interview. The ability to explain the differences and principles behind Combine or RxSwift will position you as a more senior candidate in the eyes of the interviewer.

Quiz

--- primary_color: green secondary_color: lightgray text_color: black shuffle_questions: false shuffle_answers: true --- # What is functional programming about? 1. [ ] Writing functions that may modify state as needed 1. [x] Avoiding side effects and state mutation 1. [ ] Relying on side effects to manage state transitions 1. [ ] Emphasizing object-oriented design patterns # In functional programming, why must functions avoid side effects? 1. [ ] To improve performance 1. [x] To prevent unpredictable state changes 1. [ ] To enable state mutation 1. [ ] To allow recursion # Which paradigm describes a sequence of instructions that modify the program’s state step by step? 1. [ ] Functional 1. [ ] Functional Reactive 1. [x] Imperative 1. [ ] Declarative # What is considered a side effect in a function? 1. [ ] Returning a computed value 1. [x] Modifying a variable outside its scope 1. [ ] Calling another pure function 1. [ ] Using recursion # How is state typically managed in functional programming? 1. [ ] By mutating global variables 1. [x] By transforming old state into new state 1. [ ] By ignoring state changes 1. [ ] By centralizing state in a single object # Which pattern is used by functional reactive programming? 1. [ ] Singleton 1. [ ] Factory 1. [ ] Delegate and Callback 1. [x] Publisher and Subscriber # What is the primary benefit of using pure functions? 1. [ ] They allow state mutations 1. [x] They are easier to test and debug 1. [ ] They increase code complexity 1. [ ] They require global variables # Examine the code below. Does it fully follow the functional programming principles? ```swift var value = 0 func increment(_ value: Int) -> Int { value + 1 } value = increment(value) print(value) ``` 1. [ ] Yes, it's correct 1. [ ] No, the function has side effects 1. [x] No, it mutates state by reassigning a mutable variable 1. [ ] No, it mutates the "value" variable inside the increment function

Thanks for reading. 📖

I hope you found it useful!

If you enjoy the topic don’t forget to follow me on one of my social media - LinkedIn, X, Mastodon, Bluesky or via RSS feed to keep up to speed. 🚀