Identifying Pure Functions

Is the view function shown below, a pure function?

function view(model) {
  return div([
    heading,
    `Home: ${model.home}, Away: ${model.away}`
  ])
}

I'm not sure, I need more information.

Ok, what else would you like to know?

What language is this written in?

JavaScript

What type of value is heading?

Here's where it's assigned:

const heading = header('Current Score')

Hmm, I still don't know what type of value heading is?

Take a guess. Do you think it's a primitive type (Number, String, etc..), or a non-privitive?

It's probably a non-primitive

That seems pretty reasonable to me, it almost has to be some form of an object.

What else would you like to know?

Are the div and header functions pure?

Well, they both come from a 3rd party library. The docs say they're pure functions... Let's take the authors word, and we'll assume they're pure.

Ok, back to the original question, is the view function pure?

function view(model) {
  return div([
    heading,
    `Home: ${model.home}, Away: ${model.away}`
  ])
}

It's impure

Why is that?

Well, we determined that heading is some form of an object, and objects can be mutated, in other words it's potentially stateful.

Now, since the view function depends on a stateful value that's not passed in as a parameter, it's impure.

How sure are you, any doubt in your mind?

I'm very confident

I'm going to disagree. I think the view function, might be a pure function.

Am I crazy?

Probably, but go ahead and give me an explanation

Ok, I'll give you one, but let's consider another example first.

Is the following function pure?

function add(a, b) {
  return a + b;
}

That's easy, it's a pure function.

Are you sure?

Yes, it's the canonical example of pure functions, right?

Would you believe me if I said the add function might not be pure?

Probably not, I think you should go check your temperature, I'm guessing you've got a fever

Ok, before you attack me, give me a bit of leeway and let me explain.

Technically someone could hijack the add function, as shown below:

const _add = add;

add = (a, b) => {
  launch();
  return _add(a, b)
}

function launch() {
  console.log('Missle Launched!');
}

//...

console.log(add(1, 2));
// "Missle Launched!"
// 7

That's ridiculous, nobody would do that

I agree, it seems very unlikely, but if we're being sticklers, you can't be sure that calling add will be side effect free, can you?

What's the point?

Humans don't like ambiguity. We want certainty, we want things to be black and white, but the truth is, we find ourselves in gray areas most of the time.

For instance, consider the view function you saw earlier. We determined it has characteristics that might make it impure... So most people would call it impure. But the truth of the matter is, it might be impure, and it might be pure.

It might be impure because it depends on the potentially stateful value, heading, but what if I could say with certainty, heading, never get's changed.

Wouldn't you call the view function pure in this scenario?

But how could you know with certainty, that heading never get's mutated?

Well, I can't be 100% certain, but I can have high confidence. What if the object that's returned from the header function, is frozen.

But freezing is only shallow

Ok, what if it's frozen to all depths?

Or, what if I added lint rules to my build process, that forced me to program in a functional style?

Then I could have high confidence that the heading object never get's mutated, in which case the view function would seem to be pure.

Similarly, with the add function, I could setup lint rules to prevent the hijacking of the add function.

Am I just being a contrarian

I get a lot of questions from programmers taking my courses. Many of these folks are looking for binary answers to their questions. But the truth is, many questions don't have binary answers.

For example, "is this function pure?"

Sometimes the answer is yes or no, but sometimes I'd say functions are effectively pure, but I'd hesitate to say YES they are 100% pure.

Searching for answers, can be frustrating, when we're only considering 2 possible choices. Embrace the gray areas, because that's where most of the answers are.