'What exactly is a pure function when we are talking about a function within a function

I've learned that a pure function is a function that doesn't alter global state, period. If this is true, functions within functions can alter the state of the outer function and still be pure, correct?

Example:

function func1() {
  let name = "My Name"
  func2()  

  function func2() {
    // alter name here.
  }
}

In the above example, func2 is still pure because it doesn't use any global state.

That's how I see, but my working colleagues believe that func2 is not pure, and it should be writen like:

function func1() {
  let name = "My Name"
  func2(name)  

  function func2(name) {
    // use name here.
  }
}

Which is bad, because:

  • if the v8 doesn't optimize this, the CPU will run more instructions
  • shadowing is a bad practice

The question is: What exactly is a pure function when we are talking about a function within a function?



Solution 1:[1]

Purity is not defined to care only about global variables, it cares about any non-local variables (and more) that shouldn't be mutated. An outer variable of a closure still counts as non-local, it doesn't need to be global.

So if func2 changes name, then it's impure. Whether func1 becomes impure as well through that depends on whether you consider only external purity - as long as name and func2 stay local within the function, it may still be pure.

Solution 2:[2]

A pure function is a function that meets 2 requirements:

  1. Given the same input, it will always return the same output.
  2. Produces no side effects.

Side effects can be defined as 'any application state change that is observable outside the called function other than its return value'.


To be more specific:

  • A function that modifies anything outside it's scope (even if it's not the global scope) is not a pure function.

  • In your example, if func2 modifies a variable outside its own scope, then it's not a pure function:

function func1() {
  let name = "My Name"; // <-- the variable is not in the global scope but, in any case, it is outside the scope of func2
  func2();

  function func2() {
    // alter name here.
  }
}

Solution 3:[3]

I've learned that a pure function is a function that doesn't alter global state, period.

Well, that's oversimplifying. A pure function should one, not have side effects, and two, its outcome should rely only on the arguments. So, as a corollary, no state. Your func1's name property suspiciously look like a state. Could I mutate it? Will func1() yield different results dependent of the previous calls? Impure!

Of course, func2 being impure is beyond dispute. You wrote "alters name" - 'name' is outside its scope. It's a side effect.

Solution 4:[4]

Another example I think it's worth mentioning is the follow pure function:

function insert(DB, user) {
    return function() {
        throwIfUserExists(DB, user);
        var savedUser = saveUser(DB, user);
        return savedUser;
    }
}

Note, that when you call insert, as long as you keep sending in the same DB and user, you will receive the same output as the function returns another function - no side effect happens.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bergi
Solution 2
Solution 3
Solution 4