Understanding the Difference Between OOP and FP in C#
In this chapter, we will be discussing Functional Programming (FP). Because most C# developers are accustomed to Object-Oriented Programming (OOP), the shift to FP can feel rather alien to begin with.
To make this clear, we will move away from simple shapes and look at a real-world scenario: A Shopping Cart. We will implement a simple logic to calculate the total price of items in a cart, first using the traditional OOP approach, and then using the FP approach.
The OOP Approach: Encapsulating State
In OOP, we model the world using "objects" that hold their own data (state) and have methods to modify that data.
Here is a ShoppingCart class. It holds a list of prices internally and has methods to add items and calculate the total.
The FP Approach: Pure Functions and Data
Now, let’s look at the Functional Programming version. In FP, data and behavior are separate. We don't create a "Cart" object that holds items; we just have a list of items (Data) and a function that calculates the total (Behavior).
Explanation of the Differences
To truly understand the shift, let's break down exactly what changed between the two examples.
1. State Handling
- OOP (Encapsulation): The
ShoppingCartclass "owns" the data. The list_itemsis private. You cannot calculate the total without creating an instance of the class first. The state is coupled with the logic. - FP (Separation): The data (
List<decimal>) is separate from the function (CalculateTotal). The function doesn't care where the list came from; it just calculates the result.
2. Mutability vs. Immutability
- OOP: OOP relies on change. In the example, we called
myCart.AddItem(). This method changed the internal state ofmyCart. If you checkedmyCartbefore and after that line, it would be different. - FP: FP prefers immutability. Although our simple example used a list, a strict FP approach would not "add" an item to an existing list. Instead, it would create a new list containing the old items plus the new one. This ensures that data never changes unexpectedly.
3. The "Pure Function" Concept
- In the FP example,
CalculateTotalis a Pure Function. - Definition: A function is pure if it always returns the same result for the same input and has no side effects (it doesn't change anything outside itself).
- Benefit: Pure functions are incredibly easy to test. You don't need to set up a complex
ShoppingCartobject with a specific history to test the total; you just pass a list of numbers.
Summary: Which is better?
Neither is strictly "better," but they serve different goals:
- OOP is excellent for modeling complex systems where entities (like a
User,Window, orGameCharacter) need to manage their own changing state and interactions. - FP is excellent for data processing, concurrent programming, and logic-heavy applications where you want to minimize bugs caused by unexpected state changes.
Most modern C# codebases use a hybrid approach, utilizing OOP for architecture (Dependency Injection, Services) and FP for logic (LINQ, immutable records).