Two Sides of the Same Coin: Functional vs Object-Oriented Approach in Swift
\n\nWhen I first started writing for iOS, I thought that object-oriented programming was the only right way. Classes, inheritance, polymorphism — it all sounded like a developer's holy scripture. But then I discovered functional programming in Swift, and my world turned upside down. It turns out you can write code that doesn't mutate state, that is easy to test, and that looks like a mathematical formula.
\n\nSwift is a unique language. It is multi-paradigm. This means you can mix OOP and the functional approach in one project, taking the best from both worlds. But how do you avoid confusion? When to use classes, and when to use closures and map? Let's figure it out.
\n\nObject-Oriented Swift: A Classic That Works
\n\nObject-oriented programming (OOP) in Swift is built around classes, protocols, and inheritance. It is a paradigm where data and behavior live together. You create a model — for example, a "User" — and this object itself knows how to introduce itself, how to change its name, or calculate its age.
\n\nHere is a classic example in Swift:
\n\nclass User {\n var name: String\n var age: Int\n \n init(name: String, age: Int) {\n self.name = name\n self.age = age\n }\n \n func greet() -> String {\n return "Hello, my name is \\(name) and I am \\(age) years old."\n }\n \n func haveBirthday() {\n age += 1\n }\n}\n\nlet user = User(name: "Anna", age: 25)\nuser.haveBirthday()\nprint(user.greet()) // Hello, my name is Anna and I am 26 years old.\n\nIn this code, we use the object-oriented approach in Swift. We have state (properties name, age) that can change (method haveBirthday). This is intuitive, especially if you come from Java or C++. But there is a nuance: mutable state is a source of bugs. The more objects change each other, the harder it is to debug the program.
\n\nFunctional Swift: The Power of Closures and Immutability
\n\nFunctional programming in Swift offers a different perspective. Here, functions are "first-class citizens." You can pass them as parameters, return them from other functions, and store them in variables. The main principle is pure functions, which do not change external state and always return the same result for the same input data.
\n\nLet's see how the same example looks in a functional style:
\n\nstruct User {\n let name: String\n let age: Int\n}\n\nfunc greet(user: User) -> String {\n return "Hello, my name is \\(user.name) and I am \\(user.age) years old."\n}\n\nfunc haveBirthday(user: User) -> User {\n return User(name: user.name, age: user.age + 1)\n}\n\nlet user = User(name: "Anna", age: 25)\nlet olderUser = haveBirthday(user: user)\nprint(greet(user: olderUser)) // Hello, my name is Anna and I am 26 years old.\n\nNotice: we use a struct, not a class. Structs in Swift are value types. They are copied upon assignment. The function haveBirthday does not mutate the original object; it creates a new one. This is the key idea of the functional approach — immutability.
Comparison of Approaches: When to Use What?
\n\nNow let's honestly compare OOP and functional programming in Swift. Each has its strengths.
\n\nObject-Oriented Approach in Swift
\n\n- \n
- Pros: Intuitive for modeling the real world. Great for UI components (UIViewController, UIView). Inheritance simplifies code reuse. \n
- Cons: Mutable