Skip to main content

Section 15.5 Pure functions

A function is considered a pure function if the result depends only on the arguments, and it has no β€œside effects” like modifying an argument or outputting a value. The only result of calling a pure function is the return value.
Let’s consider an increment function that changes a time like 3:48 to 3:49 or 11:59 to 12:00. We have two ways we could design the function. It could be a pure function that returns a new time or a modifying function that takes a time by reference and changes it.
First lets consider a pure version of the function. It takes a Time by const reference. It then makes a copy of the time, modifies the copy, and returns it:

Checkpoint 15.5.1.

Run the Codelens and answer the questions it asks.

Note 15.5.1.

Codelens does not support format. Normally we would want to use format({:0>2}, time2.minute) to make a 0 minute value print as 00.
We could also write a pure function using pass by value. With pass by value, the parameter is already a copy of the argument that was passed in. So we don’t need to explicitly make a copy of the parameter to modify:
Listing 15.5.1.
Now lets consider a modifying version. It takes a Time by reference and modifies it. Because the parameter is a reference, changing in actually changes the argument that was passed to the function. In this case, that means the time variable in main. The function does not return anything - the whole point of it is the β€œside effect” of changing the parameter.
Listing 15.5.2.
If the caller is using a pure function, and wants to change an existing time, it can use an assignment to store the new value into an existing variable:
So which approach is best? Pure functions help to maintain the abstraction of a function. When a function does nothing but give us an answer, we don’t have to worry about what else might be going on behind the scenes. You do not ever have to worry about there possibly being hidden interactions between various functions because one function made some hidden change to the program’s state that then changes how the next function behaves.

Note 15.5.2.

There are programming languages, called functional programming languages, that only allow pure functions. These languages are designed to make it easier to write bug free code, and to write tests to prove that the code is correct by compltely eliminating the chance of side effects.
However, pure functions can be less efficient. Our pure increment function must make a new Time struct each time we call it. This is more work than just changing a number or two in an existing struct, which the modifying version does. In situations where we have a large struct with many member variables and want to have a function that only changes one of the variables, it can be wasteful to make a copy.
In general, you should favor pure functions for smaller structs (where the efficiency differences aren’t as extreme) or situations that clearly imply that a new value or copy are being made. Favor modifying functions when you make are making small changes to a large existing struct or the situation clearly involves changing an existing value and then not caring about the old value. Do try to stick to one approach or another. You should not both modify the input and return a new value in the same function.
The caller will have to adapt to the approach used by the function. A pure function returns a new value, so if the caller wants to modify a variable they need to assign the result of the function back to that variable:
Time time = { 11, 59 };
// Get the new time and store it as new value for old variable
time = incrementPure(time);
// time is now 12:00
And, if the function is modifying, but the caller does not want their data to change, they can make their own copy before calling the function:
Time time = { 11, 59 };
// Make a copy of the time and modify the copy
Time newTime = time;
increment(newTime);
// time is still 11:59, newTime is 12:00

Checkpoint 15.5.2.

What situations would be good ones to use a modifying function (as opposed to a pure function)?
  • To modify a large piece of data
  • Correct!
  • To modify a small piece of data
  • When working with smaller pieces of data, the efficiency difference between the two approaches is not as extreme.
  • When trying to minimize complexity.
  • Modifying functions tend to make the code more complex. You have to worry about what the function is doing to the data and how that might affect other parts of the program.

Checkpoint 15.5.3.

You have attempted of activities on this page.