Functional-Light JavaScript, v3

Pure Functions & Constants

Kyle Simpson

Kyle Simpson

You Don't Know JS
Functional-Light JavaScript, v3

Check out a free preview of the full Functional-Light JavaScript, v3 course

The "Pure Functions & Constants" Lesson is part of the full, Functional-Light JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle continues to refine the definition of pure functions by explaining how constants reduce the purity of functions. Then, Kyle explains how their readability is also harmed by forcing the reader to understand the whole program as opposed to just one line.


Transcript from the "Pure Functions & Constants" Lesson

>> Kyle Simpson: So these pure functions that we're talking about, what does that mean? What do we mean by a pure function? Well, the first way we could define a pure function is as we have designed so far, it is the function in this spirit of functional programming. It is a function that takes all of its inputs as direct, all of its outputs as direct, and it has no side effects.

That's the first way of thinking about a pure function, but remember and we'll come back to this in a bit. Remember, that I've pointed out it's not about the function definition itself for JavaScript, but rather about the function call. There really isn't such a thing as a pure function per se there is a pure function call.

And that's the thing that we wanna go after, we want pure function calls. So yes, we could look at the addTwo function, and if we were to call it with two inputs and get a single output out, that would be a pure function call. addAnother here however, line 7, it takes two inputs, yes, but notice how it also uses a z variable that's outside of itself.

>> Kyle Simpson: So that's an indirect input. And in the strictest sense, using an indirect input invalidates something about the nature of what we were supposed to be able to expect about this function. We're supposed to be able prove and predict its behavior. And because we're relying upon a side cause, a side effect, now we can't really be as sure.

We can't really prove it through the math in the same way.
>> Kyle Simpson: So that's the kind of thing that we want to be aware of, is if we're accessing variables outside of our self is that in validating, is it removing, is it watering down those benefits from functional programming for us?

It's more complicated than that, though. It's not just that we can't access a variable outside of ourselves. We talked about all the other kinds of side effects like generating random numbers and all of that other stuff. But it's also the case that we could access a variable outside of ourself and not invalidate our function purity, it is more complicated.

But that's a clear signal, it's like a usual suspect that keys you in, if you see an access of a variable outside, immediately you should be asking yourself why, why is that? Is that necessary, is that useful, is that important?
>> Kyle Simpson: Because the code might look like this.

The code might have a z variable in the outer scope and in this case, line 1, it's a constant, z = 1. Now, if on line 8 instead of accessing z, if I had accessed just the value, if I'd said add to x, y, and then just said plus 1, we would all say no problem.

That looks like a pure function, no side effects, no side causes. So is the introduction of z here really a side cause or not? Cuz if we think about what a constant is supposed to be, a constant is supposed to be a semantic placeholder for a value. And especially since we're using the const keyword, but even if we weren't, because it is a constant, it doesn't change throughout the lifetime of the program.

>> Kyle Simpson: So really is it invalidating this as an impure function, or is addAnother simply referring to a semantic constant placeholder here?
>> Kyle Simpson: If you could convince yourself that line 11 is a pure function call, and there will be more layers of meaning to what we mean by pure function call.

But here addAnother does in fact returned to us the value 42 when we pass in 20 and 21, and it doesn't change anything else about the state of the program,. So it doesn't cause any side effects, and it doesn't use any side effects other than this constant. And I would submit to you that it is therefore still consistent with functional principles.

>> Kyle Simpson: That line 11 still counts as a pure function call, even though we're accessing a variable outside of ourselves. Now, you may be able to convince yourself that that is true because I pointed out that we're using the const keyword. But when I switch it up and I say, what if I use the var keyword?

Some of you may be saying, well, now it's not a pure function call, really? Is my choice of const verses var here actually going to impact the readability of this program. Some say yes, but am gonna say, I don't think so. And here is the reason and this is critical for all the rest of our discussion.

If it were possible for me to show you a code snippet that only had part of the program, and I were to ask you questions about it, and I was only showing you part of the program. Then you could say virtually anything, because just about anything else could also be true in that other part that I was hiding from you, right?

So its in a sense not useful to discuss a program unless we're discussing it in its entirety. For our purposes of our discussion in this course we need to assume that we see the entire program. So let me ask you the question, anywhere in this program does z ever get re-assigned?

We can see all the lines of code and we know that it doesn't get reassigned. So let me ask you a question, is z serving the purpose of a constant in this program?
>> Kyle Simpson: I would submit that it is, whether use the const keyword or not it is a constant in practice.

And therefore, every bit as much in the spirit of functional program. Now I know many functional programmers, that are absolutely enamored with the const keyword, they use it all over the place. I don't think the const keyword buys anything for the functional programmer. Because the real important key is, is the variable getting reassigned, not can it be reassigned or not?

>> Kyle Simpson: And in fact, more important even than whether it gets assigned, or can it be reassigned is, is it obvious to the reader that it can't be reassigned, that it doesn't get reassigned, is that obvious? Const has some problems because it looks like it is making values that don't change when actually it's making variables that get reassigned.

And we're gonna come back to that topic when we talk about immutability. But I would submit to you that in this program, z still serves that role and therefore, addAnother is still when it's called on line 11 that's pure a still function call.
>> Kyle Simpson: But none of you seem to raise your hand and yell at me, wait a minute, why is it a pure function when we're using another variable called addTwo, which is a variable that happens to reference a different function.

You see how easily you just skipped right over the usage of that variable and zeroed in on the z variable and said, wait a minute, that one that's a problem. Why is it that we get to use the addTwo variable? Just because it points to a function? I have news for you, the addTwo variable, the identifier that points at that function from line 3, that identifier is not a constant.

It is in fact possible that addTwo could get reassigned somewhere to a different function definition. So it's no more a constant than is var z, and yet we can still say that in this program, we can see that addTwo does not get reassigned. And so the behavior of line 11, is still that we observably have a pure function call.

>> Kyle Simpson: Functional programmers, by the way, they do this all the time. And I don't hear them talk much about it, it's just one of those things that they assume you get. That if you're referencing a thing that doesn't ever change, it's exactly as if it had been in lined, which is the whole point of constants.

>> Kyle Simpson: Functional programmers use functions inside of other functions all the time and they don't always pass those functions in. You don't always see the 14 lambda utilities getting passed in as inputs to a function, and yet you can still use them. Because it is assumed that lambda and all of the methods on lambda are in practice, constants.

Meaning that they don't change their definition throughout the lifetime of the program. And why I'm hammering on this point is because it emphasizes our responsibilities the author of the code to make it as obvious as possible that something is a constant.
>> Kyle Simpson: That it's gonna behave as a constant.

One way you could do that is with the const keyword, but I don't think that's the more effective way to do it.
>> Kyle Simpson: Matter of fact, because of the baggage that const comes with, I don't think it's actually serving a net benefit to your program, more on that later as I promised.

But whether you use the const keyword or not, if you make it obvious for the reader that it's gonna behave as a constant, that's the key, why? Why though, it's because we want the reader of our code to understand, I don't need to worry that that thing changed.

If they were trying to understand line 8 and they didn't know that z was a constant, well now all of a sudden they're like, they're dealing with all the problems that you have to deal with when you juggle side effects on your head, right? As a matter of fact, if they really didn't know whether z got reassigned or not, how many lines of code would they have to execute to convince themselves what line 11 would do?

Well, actually they have to mentally execute lines 1 through 10 to get to that point, because theoretically at least, any of those lines could have changed z.
>> Kyle Simpson: So if they're not sure whether it's going to stay that same value it's going to act as a constant, then essentially to read your code means they have to execute everything before that line to understand that line.

That's the real problem with side effects, is that it creates this outcome which is that to understand any given line, we have to mentally execute everything before it so that we know what state the program was in before we ran it. But if the addAnother function call is reliably and obviously pure, then I can execute line 11 completely in isolation of all the rest of the program.

Not only do I not need to run anything before line 11 to figure out what line 11 does, I also don't need to worry that line 11 is gonna affect anything else in the program. And that's the real benefit of a pure function call, it isolates that line so that I can analyze it independently.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now