This course has been updated! We now recommend you take the Functional-Light JavaScript, v3 course.
Transcript from the "Evolving Understanding of Impurity" Lesson
[00:00:00]
>> Kyle Simpson: I wanna dig in a little bit more and try to evolve our understanding of function purity even further. Here's a function foo that takes a direct input x and it references a variable y from outside of itself, it's using a const y, we're gonna get to const later.
[00:00:18] But let's just say for now const creates a y that is not going to ever be changed. So my question to you is based on our current understanding of function purity is foo a pure function?
>> Speaker 2: I'm going to say no.
>> Kyle Simpson: Okay, so I'm hearing no. We'll ask you to explain that no in a moment, does anybody disagree and think that it is a pure function?
[00:00:50]
>> Kyle Simpson: It's not, because it's relying on something not being passed in. So based on our original definition the red side of the rubiks cube we say that it can access something outside of it self right? But that second definition I just gave you was .well actually the important part of function period could be more accurately stated as given the same input we always get the same output.
[00:01:16] Given the same input here, are we always gonna get the same output? Is there anything that could happen to this program that would prevent us from getting two whenever we call one. Whenever we call it with the value 1.
>> Speaker 2: Aside from someone changing the value of y.
[00:01:43]
>> Kyle Simpson: No, I'm saying given the state of this code, and const y can't be reassigned. So given the state of the code as written, if we just called line 7 over, over, and over again, is there anything that could happen that would change to make it not return the value to?
[00:01:59]
>> Speaker 2: Couldn't you execute that function somewhere else in another script or import a different script or something like that where y has changed?
>> Kyle Simpson: Well fortunately, we talked about lexical scope in the deep JavaScript foundations course. Lexical scope says, this foo as written here will close over that y, and that y is never going to change.
[00:02:25]
>> Kyle Simpson: So it doesn't matter if we passed foo around as an event handler or whatever, it's closed over that exact y.
>> Kyle Simpson: There's nothing about this program as written that could happen at runtime that would change the behavior of line 7. Going to run that way every single time from that perspective, from the blue side of the rubics cube then, foo acts as a pure function.
[00:02:59] What about this code, we have a foo function that calls bar with x, and bar takes in an input and computes an output and returns it.
>> Kyle Simpson: Let's first ask, is bar a peer function? Yes.
>> Kyle Simpson: Somebody tell me why bar is a pure function.
>> Speaker 2: Cuz it's not usually in the [INAUDIBLE] side scope.
[00:03:26]
>> Kyle Simpson: That's one way of stating it but what's our new evolved definition for a pure function?
>> Speaker 3: It will return the same thing every time it's run.
>> Kyle Simpson: Given a bar function written like that, if I pump in the value 11, I'm always gonna get 12 out right?
[00:03:40] So given the same inputs I'm always gonna get the same output, so if bar is pure that's a good start. Cuz if bar was not pure we could immediately say that foo is not pure. Bar's pure, now let's talk about foo, is foo satisfying our definition of function purity?
[00:04:08]
>> Kyle Simpson: Given what we see written here, every time I call foo with value one, I'm always gonna get value two out right? As a matter of fact there's really only one thing that could possibly change here that would effect the would be if somebody redefined bar. If somebody took the identifier bar and redefined it to point to a different function, all of a sudden we get a different output.
[00:04:36] We do not see that happening so given what we can see in this program. The function foo is satisfying out definition of function purity.
>> Kyle Simpson: But this is starting to introduce, and this should feel uncomfortable, I'm actually intentionally creating something for you to rustle with. So don't feel like you're the weird one out that doesn't understand what's going on.
[00:04:59] This is intentional, I'm trying to create some tension here, so that you have to wrestle with this concept. Our initial definition would've told us it's impure cause' it references a variable outside of itself. Our evolved addition says, well it's observably pure. If we were to take the original definition in it's strictest sense, that would mean that every single function would not only have to have all its inputs, but any function it used would also have to be an input.
[00:05:32] That could get rather onerous pretty quickly, right? If one function couldn't call another function, so I believe in the spirit of what we're doing here. We're evolving our understanding of functional purity closer and closer to what a functional programmer says is functional purity. And here we observe that we are still consistent with that in that foo will always produce value two if given the value one.
[00:06:01]
>> Kyle Simpson: Now it is technically possible for somebody to rewrite the bar function. Some people do that if you've ever looked at the internals of lowdash for example, they rewrite functions, they hotswap in. Compile versions of functions and do all kinds of tricks for performance and stuff, I never rewrite functions in my program.
[00:06:20] I just, as a rule of thumb, never ever ever do that. I don't care that I could squeak out another microsecond of performance or something, I just don't rewrite functions. I treat functions as if they are constants, as if they are things that will not be redefined. So in my code you'll never gonna find that function getting re written there at runtime to a different definition.
[00:06:46] You're not gonna find that in my application code and therefore in my application code where you to see this pattern, you can reasonably trust the bar if going to add for the constant. and given what we see in the program, we clearly do not see bar being rewritten, so therefore, we can trust it.
[00:07:05] Is it a 100 percent, iron clad guarantee, I don't know about that and here's the point that I'm trying to make. Function purity in a mutable system like JavaScript Is not actually a binary characteristic. You cannot say something is 100% pure or 100% impure. Well, you might be able to say it's 100% impure, but you definitely cannot say, for virtually any function, for the vast majority of functions you can't actually say it is pure.
[00:07:38] What you actually have to say is Purity is a confidence level, it's a range. Do I have a strong degree of confidence that foo is going to act pure? I would say I have a very strong degree of confidence given what I see here in this code. Would you agree with that?
[00:07:58] Would you understand where I'm coming from? That it's a strong degree of confidence. I'm gonna leave myself a little window there, that it is technically possible for somebody to do some kind of crazy thing and write a macro or something that changes what functions do or some crazy thing like maybe.
[00:08:13] But given what I see in this program, I'm pretty confident that fools gonna behave as pure. What about this code?
>> Kyle Simpson: Here foo in pass in a function called bar and I return an new function back and that new function takes in an x and when it receives the x it calls the original bar with it.
[00:08:43]
>> Kyle Simpson: So my foo down on line seven takes in a function callback. Returns us back a function and then that second set of parenthesis on line nine executes the return function passing in the value three as the parameter x. And we get three coming in as the parameter v on line 7 doubled, gets returned back and we get the value 6 as the output.
[00:09:10]
>> Kyle Simpson: So my question here is, given what we now know about function purity, is foo a pure function?
>> Kyle Simpson: There's actually two questions to ask here, was wondering if anybody would catch it. Foo itself is a thing that given some function it just returns another function. So the first question is given any given function that we pass into foo, are we always gonna get back another function that's wrapped around it in exactly the same way.
[00:09:45] Line two creates a function that wraps around whatever bar we pass in, and that function is what we return back. So if I didn't have those parentheses set on line nine, and I just called foo, and I called it over and over again with that exact same function.
[00:09:59] Is the resulting coming back always going to be exactly the same structure?
>> Kyle Simpson: I have a high degree of confidence, so you better not tell me yes or no anymore. Because there is no yes or no here, there is a, I have a high degree of confidence, I have a low degree of confidence, I have a mid degree of confidence.
[00:10:23] Pick whatever scale you wanna use, but in a mutable environment like JavaScript, there's virtually no such thing as 100% pure.
>> Kyle Simpson: So we could say foo is pretty much always gonna return it. Now given that output function. The one from line two that we are calling on line nine- Is that output function pure?
[00:10:45] There are two functions to ask that about. We're now asking about the second one- the one we can pass in the value three as the parameter x. Is that one pure?
>> Kyle Simpson: If that one was closed over a bar, and we gave some x value of 3 to it, are we always gonna get back 6?
[00:11:15]
>> Speaker 2: I have a high degree of confidence that we will.
>> Kyle Simpson: , You have a high degree of confidence that's the correct answer. Okay, this is a strong degree of confidence that these, both of these functions are behaving as pure okay,
>> Kyle Simpson: What about this function?
>> Kyle Simpson: I mean I'd say with a high deal of confidence that it would return the same based on the input, that you will get the same output.
[00:11:46] If we gave it the same object structure every time, do you we feel like it's always gonna extract the id property and give us that same id value back?
>> Speaker 2: Yes. So, you would say I have a relatively high degree of confidence?
>> [INAUDIBLE]
>> Kyle Simpson: What is I give it an object where id is a getter that returns a random number?
[00:12:14]
>> Kyle Simpson: Now where's your confidence level?
>> Speaker 2: [LAUGH]
>> Kyle Simpson: Shattered.
>> Speaker 2: [LAUGH]
>> Kyle Simpson: [LAUGH] Shattered. I should have put that word on the slide, shattered. [COUGH] I'm trying to make a point here that you have to look at what you are given on a code. And judge for yourselves what degree of confidence you have.
[00:12:36] I'm deliberately doing something weird here to push it to the edge to where it doesn't behave the way we might have assumed. But you cannot look at something in isolation in a language like JavaScript. You have to look at the full context to make those decisions. If you look only at line two You'll come up with the wrong conclusion, and you'll have a high degree of confidence and then you'll get bitten by it.
[00:13:02] And you'll be like, my world just fell apart, my world just shattered, okay. Looking at the whole context of what we're given in the program, that's how we need to judge can I trust this code or not. The whole purpose of our asking about function purity is, can we trust it?
[00:13:20] Cuz if we can't trust it, we can't understand it, you know how we talked about side effects before? Guess what another side effect is? Randomness, randomness is a side effect, it's a side cause, but it's a side effect, timestamps
>> Speaker 2: Those are side effects because, you call it over and over again, eventually your time stamp is going to change.