Transcript from the "Challenge 1: Solution" Lesson
>> Kyle Simpson: Exercise 1. Hopefully you read the read me. The read me says make a pure function bar that wraps around foo. Then part 2, make a pure function bar that adapts foo. Like I showed that capital f in the previous slides. That adapts foo to void its side effects.
[00:00:15] So, foo here is an impure function because it does take a single input x but it also uses y as an input. Can you see why it's using y as input? Because y++ on line 2 takes the current state of y into account. So that's a side cause and it also mutates y so that's a side effect.
[00:00:42] So line 2 is both a side cause and a side effect, an indirect input and an indirect output. And also line 3 is a side effect, a side output, an indirect output because we're changing the state of z. So there's one side cause and two side effects, in this example.
>> Kyle Simpson: So our first approach could be to look at what is the universe that foo touches. Well it touches a y variable and a z variable and it uses as an x as an input. So in other words, x and y are its input, z as its output.
[00:01:18] That is its universe. So if we create a bar, we need to make x and y the inputs, and we need to capture that z so that we don't allow that z changed to seep outside of the boundary of our bar function. So I have x and y as inputs, I have a var z that's gonna capture things lexically.
[00:01:39] I call that foo function from line 7 that is impure. And then, I capture the output state which is the y and the z variables are outputs. I capture that state and return it as an array. Now some may wonder, why do I need to return y? When it's because we are using y as an input to this call which means the program might need that outputted state of y as the input to the next call.
[00:02:07] So anything that could be used as an input needs to be made into an output. So I return both of those values. Now we see on line 13 that [COUGH] if I call bar with the values 20 and 5, I'm gonna get an array of 6 and 120 back.
[00:02:26] Now if I took those outputs and mapped them into some variables, and then I used one of those variables, like for example, the y value. If I use that y value of 6 as my input to the next call, which is line 15 I have actually tracked a state change in my program.
[00:02:45] So I don't mean to suggest that functional programs don't have state change, they absolutely have state change. All programs have to have state that changes throughout the course of the program. Otherwise why write the program? But what I am saying is that a functional programmer says I don't want my state to change implicitly.
[00:03:05] I don't want to call some method and somewhere under the covers, something changes. What I want to do is call something, compute my new state and give that back to me so that I can take that back and specifically decide what to do next. I want to explicitly track my state changes rather than implicitly do so.
[00:03:23] There was some back channel discussion in the chat room over the working on this exercise, it was asking about React and set state, and thing like that. To be honest with you I'm not a React programmer, so I'm not gonna commend specifically on how React works and whether that is or is not impure, something like that.
[00:03:41] I can tell you some almost unchanging facts. Like if it doesn't return something, it's impure. It's not a function, it's a procedure, right. But it's possible, at least in theory, that a system as complex as something like React or Redux. Can allow you to call something and get your new state back, as opposed to changing your state, and then let you decide what to do with that state.
[00:04:07] And then you can call another thing with state and get a new state back. That would be a functional programmer's approach to tracking state change.
>> Kyle Simpson: Some other things that I want to observe here, again, trying to provide a bit more to our definition, our running definition that we've got of functional purity.
[00:04:31] Another way of thinking about or articulating what functional purity here is, is that every time I call bar with the inputs 20 and 5, I'm going to get that exact same output which is the array 6120. So another way of articulating what is a pure function? Every time I call it with the same inputs I get the same outputs.
>> Kyle Simpson: No matter where I call it, if I give it the same inputs I get the same outputs. No matter how many times I call it. Same inputs, same outputs.
>> Kyle Simpson: That's just another way, that's another angle on the Rubik's Cube, it's another side to the Rubik's Cube.
[00:05:11] It's another way of saying what we said before, which is, it doesn't have any observational reliance upon variables outside of itself. A conclusion that we could make from that then, is a function, when we call it with the same inputs, we're always gonna get the same outputs.
>> Kyle Simpson: Alright, part two of the exercise was instead of wrapping this in a pure function, to create an interface function.
[00:05:34] So make bar take advantage of capturing or take care to capture it's current state. So that's what bar is gonna do. We're gonna take X and Y's inputs again. These are the current X and Y. I need to capture the original state of Y and Z, and the reason I don't need to capture an original X is cuz there never was a public X.
[00:05:55] X was already an input. But I do need to capture the original state of y and z. Even if they're undefined I need to capture that state. I'm using a ray destructuring here on line seven just to save myself some lines of code. So I'm saying the y and z I want to assign to a ridge y and a ridge z.
[00:06:13] Now I need to make sure that that state is in the state it should be, so I set y to the current y. And I call that foo. That side effecting function foo giving it the inputs of corrects. Then on line 10, I capture the new state of the world witch is the Y and Z variables that have been changed.
[00:06:34] I capture that new state. Line 11, I restore the original state from before I called. Line 12, I return that new state as an array so that the calling code can use that new state.
>> Kyle Simpson: At the bottom, we still have exactly the same behavior here, which is that when we call line 17 with the values 20 and 5, we're gonna get back an array of 6 and 120.
[00:07:05] And no matter how many times we call that function if we give it that same input we're always gonna get that same output.
>> Kyle Simpson: So in both cases, based upon our existing current definition, our evolving definition for function purity, the bar function is pure. It behaves as pure.
>> Speaker 2: There's a clarification in chat or [INAUDIBLE] I guess.
>> Kyle Simpson: If foo was incrementing X with X++, we would have to return it and bar along with Y and Z. Yeah, not only would we have to, okay. So let me clarify. That question is saying, if foo changed x, would we need to do something with that?
[00:07:51] No we would not, not in the way the current program works, because x is not in the outer scope and it isn't observable. It's not a returned output. So even if x changed values along the way through out that program, that's not affecting the outside code. It would not be observable and therefore doesn't need to become and output that we capture and return to the calling program.
[00:08:18] That state is hidden entirely within side of the scope of foo. So as written, we would not need to. If x were not an input, if we were using x as an indirect input and we were changing it, then we absolutely would need to capture it. But because it was a direct input and because it wasn't already affecting anything in the outside world.
[00:08:39] Any changes to it would have been unobservable before. We don't need to worry about those changes now.