Most sources define a pure function as having the following two properties:
It is the first condition that concerns me. In most cases, it's easy to judge. Consider the following JavaScript functions (as shown in this article)
Pure:
const add = (x, y) => x + y;
add(2, 4); // 6
Impure:
let x = 2;
const add = (y) => {
return x += y;
};
add(4); // x === 6 (the first time)
add(4); // x === 10 (the second time)
It's easy to see that the 2nd function will give different outputs for subsequent calls, thereby violating the first condition. And hence, it's impure.
This part I get.
Now, for my question, consider this function which converts a given amount in dollars to euros:
(EDIT - Using const
in the first line. Used let
earlier inadvertently.)
const exchangeRate = fetchFromDatabase(); // evaluates to say 0.9 for today;
const dollarToEuro = (x) => {
return x * exchangeRate;
};
dollarToEuro(100) //90 today
dollarToEuro(100) //something else tomorrow
Assume we fetch the exchange rate from a db and it changes every day.
Now, no matter how many times I call this function today, it will give me the same output for the input 100
. However, it might give me a different output tomorrow. I'm not sure if this violates the first condition or not.
IOW, the function itself doesn't contain any logic to mutate the input, but it relies on an external constant that might change in the future. In this case, it's absolutely certain it will change daily. In other cases, it might happen; it might not.
Can we call such functions pure functions. If the answer is NO, how then can we refactor it to be one?
The dollarToEuro
's return value depends on an outside variable that is not an argument; therefore, the function is impure.
In the answer is NO, how then can we refactor the function to be pure?
One option is to pass in exchangeRate
. This way, every time arguments are (something, somethingElse)
, the output is guaranteed to be something * somethingElse
:
const exchangeRate = fetchFromDatabase(); // evaluates to say 0.9 for today;
const dollarToEuro = (x, exchangeRate) => {
return x * exchangeRate;
};
Note that for functional programming, you should avoid let
- always use const
to avoid reassignment.