The second core concept in functional programming is the clear division between data and functions, setting it in contrast to object-oriented programming where these two are often closely intertwined.
Let's start by defining what we mean by data here. Data, in our context, encompasses any information that a program holds. It could be employee details in a payroll system, car specifications on a used car website, or character attributes in a video game. Essentially, it encompasses all the program's information.
In object-oriented programming, this data is typically encapsulated within objects as member variables, and it's usually accessed or modified using the object's methods.
Now, consider what functions entail. A function, in this context, is an operation applied to the data, transforming it into meaningful information. For example, you might want to calculate the average salary of programmers in your company, filter cars made after a specific year on a car website, or check if two characters collide in a video game.
class Person: def __init__(self, name, age): self.name = name self.age = age def increase_age(): self.age += 1 def change_name(new_name): self.name = new_name
person = { 'name': 'Sharon', 'age': 34 } def change_name(person, new_name): ... ...
In object-oriented programming, functions often coexist with data within objects, enabling you to manipulate or retrieve data through these functions.
In functional programming, however, functions are entirely independent of the data they operate on. This means that, to work with specific data, you must pass it as arguments to the function instead of using the 'self' keyword as you would in object-oriented programming.
Additionally, due to the immutability principle, these functions should never alter the data they receive; instead, they return a modified copy. In Python, this is facilitated by the fact that most arguments are passed by reference.
If you come from an object-oriented background, the emphasis on separating data and functions in functional programming may initially appear unusual. After all, a key tenet of object-oriented programming is encapsulating data and its related functions within objects. To understand why functional programming advocates data-function separation, it's worth revisiting why object-oriented programming promotes their amalgamation.
The primary reason for keeping data and functions together within objects is to allow interaction with member variables without directly manipulating them. Why avoid direct manipulation of member variables? Well, when programmers have unrestricted access to variables, they can and often will make unintended changes. Consider a simple example: a 'person' object with publicly accessible properties like 'first name,' 'last name,' and 'initials.'
Initially, when an instance of this class is created, the 'initials' property is correctly set. However, if programmers are granted direct access to these properties, they must remember to update 'initials' every time 'first name' or 'last name' changes, which they are likely to forget at some point, introducing bugs into the program.
The usual solution is to make variables private, often by prefixing them with underscores in Python, and allow access only through member functions. These functions ensure that variables remain up-to-date.
Functional programming takes a different approach, keeping data constant and immutable. In the absence of constants (as found in some other languages), Python follows suit.
In functional programming, if you need to modify data, you create a new constant representing the updated information. You then use this updated constant in all future calculations, ensuring clarity about the data it represents.
Let's explore this with an example. Imagine creating a simple to-do list program that helps people manage tasks. In an object-oriented approach, we'd create a 'to-do item' class containing properties like 'name' and 'completed,' along with functions like 'change name' or 'mark as done.'
We might also have a 'to-do list' class holding a list of 'to-do items' and functions for adding, removing, or sorting items.
In functional programming, data and functions are kept distinct. Instead of encapsulating data properties within classes, we often represent data using structures like lists or dictionaries.