8.1 What is shared mutable state and why is it problematic?
Shared mutable state works as follows:
- If two or more parties can change the same data (variables, objects, etc.).
- And if their lifetimes overlap.
- Then there is a risk of one party’s modifications preventing other parties from working correctly.
Note that this definition applies to function calls, cooperative multitasking (e.g., async functions in JavaScript), etc. The risks are similar in each case.
The following code is an example. The example is not realistic, but it demonstrates the risks and is easy to understand:
function logElements(arr) {
while (arr.length > 0) {
console.log(arr.shift());
}
}
function main() {
const arr = ['banana', 'orange', 'apple'];
console.log('Before sorting:');
logElements(arr);
arr.sort(); // changes arr
console.log('After sorting:');
logElements(arr); // (A)
}
main();
// Output:
// 'Before sorting:'
// 'banana'
// 'orange'
// 'apple'
// 'After sorting:'
In this case, there are two independent parties:
- Function
main()
wants to log an Array before and after sorting it. - Function
logElements()
logs the elements of its parameterarr
, but removes them while doing so.
logElements()
breaks main()
and causes it to log an empty Array in line A.
In the remainder of this chapter, we look at three ways of avoiding the problems of shared mutable state:
- Avoiding sharing by copying data
- Avoiding mutations by updating non-destructively
- Preventing mutations by making data immutable
In particular, we will come back to the example that we’ve just seen and fix it.